home *** CD-ROM | disk | FTP | other *** search
/ Enter 2007 April / ENTER_CD_04_07.iso / Internet / WinHTTrack 3.23 / httrack-3.23.exe / {app} / src / htslib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-03-08  |  119.0 KB  |  4,461 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Fichier librairie .c
  38.  
  39. #include "htslib.h"
  40. #include "htsbauth.h"
  41.  
  42. /* specific definitions */
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsbauth.h"
  46. #include "htsthread.h"
  47. #include "htsnostatic.h"
  48. #include "htswrap.h"
  49. #include <stdio.h>
  50. #if HTS_WIN
  51. #include <direct.h>
  52. #else
  53. #ifdef HAVE_SYS_TYPES_H
  54. #include <sys/types.h>
  55. #endif
  56. #ifdef HAVE_SYS_STAT_H
  57. #include <sys/stat.h>
  58. #endif
  59. #ifdef HAVE_UNISTD_H
  60. #include <unistd.h>
  61. #endif
  62. #endif
  63. #include <stdlib.h>
  64. #include <string.h>
  65. #include <time.h>
  66. #include <sys/timeb.h>
  67. #include <fcntl.h>
  68. // pour utimbuf
  69. #if HTS_WIN
  70. #include <sys/utime.h>
  71. #else
  72. #include <utime.h>
  73. #endif
  74. /* END specific definitions */
  75.  
  76.  
  77.  
  78. // DΘbuggage de contr⌠le
  79. #if HTS_DEBUG_CLOSESOCK
  80. #define _HTS_WIDE 1
  81. #endif
  82. #if HTS_WIDE_DEBUG
  83. #define _HTS_WIDE 1
  84. #endif
  85. #if _HTS_WIDE
  86. FILE* DEBUG_fp=NULL;
  87. #define DEBUG_W(A)  { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
  88. #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
  89. #endif
  90.  
  91. /* variables globales */
  92. int _DEBUG_HEAD;
  93. FILE* ioinfo;
  94.  
  95. #if HTS_USEOPENSSL
  96.  SSL_CTX *openssl_ctx = NULL;
  97. #endif
  98. int IPV6_resolver = 0;
  99.  
  100.  
  101. /* dΘtection complΘmentaire */
  102. const char hts_detect[][32] = {
  103.   "archive",
  104.   "background",
  105.   "data",         // OBJECT
  106.   "dynsrc",
  107.   "lowsrc",
  108.   "profile",      // element META
  109.   "src",
  110.   "swurl",
  111.   "url",
  112.   "usemap",
  113.   "longdesc",     // accessibility
  114.   "xlink:href",   // xml/svg tag
  115.   ""
  116. };
  117.  
  118. /* dΘtecter dΘbut */
  119. const char hts_detectbeg[][32] = {
  120.   "hotspot",      /* hotspot1=..,hotspot2=.. */
  121.   ""
  122. };
  123.  
  124. /* ne pas dΘtcter de liens dedans */
  125. const char hts_nodetect[][32] = {
  126.   "accept-charset",
  127.   "accesskey",
  128.   "action",
  129.   "align",
  130.   "alt",
  131.   "axes",
  132.   "axis",
  133.   "char",
  134.   "charset",
  135.   "cite",
  136.   "class",
  137.   "classid",
  138.   "code",
  139.   "color",
  140.   "datetime",
  141.   "dir",
  142.   "enctype",
  143.   "face",
  144.   "height",
  145.   "id",
  146.   "lang",
  147.   "language",
  148.   "media",
  149.   "method",
  150.   "name",
  151.   "prompt",
  152.   "scheme",
  153.   "size",
  154.   "style",
  155.   "target",
  156.   "title",
  157.   "type",
  158.   "valign",
  159.   "version",
  160.   "width",
  161.   ""
  162. };
  163.  
  164.  
  165. /* dΘtection de mini-code javascript */
  166. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  167. const char hts_detect_js[][32] = {
  168.   "onAbort",
  169.   "onBlur",
  170.   "onChange",
  171.   "onClick",
  172.   "onDblClick",
  173.   "onDragDrop",
  174.   "onError",
  175.   "onFocus",
  176.   "onKeyDown",
  177.   "onKeyPress",
  178.   "onKeyUp",
  179.   "onLoad",
  180.   "onMouseDown",
  181.   "onMouseMove",
  182.   "onMouseOut",
  183.   "onMouseOver",
  184.   "onMouseUp",
  185.   "onMove",
  186.   "onReset",
  187.   "onResize",
  188.   "onSelect",
  189.   "onSubmit",
  190.   "onUnload",
  191.   ""
  192. };
  193.  
  194. /* dΘtection "...URL=<url>" */
  195. const char hts_detectURL[][32] = {
  196.   "content",
  197.   ""
  198. };
  199.  
  200. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  201. const char hts_detectandleave[][32] = {
  202.   "action",
  203.   ""
  204. };
  205.  
  206. /* ne pas renommer les types renvoyΘs (souvent types inconnus) */
  207. const char hts_mime_keep[][32] = {
  208.   "application/octet-stream",
  209.   "text/plain",
  210.   ""
  211. };
  212.  
  213. /* pas de type mime connu, mais extension connue */
  214. const char hts_ext_dynamic[][32] = {
  215.   "php3",
  216.   "php",
  217.   "php4",
  218.   "php2",
  219.   "cgi",
  220.   "asp",
  221.   "jsp",
  222.   "pl",
  223.   /*"exe",*/
  224.   "cfm",
  225.   ""
  226. };
  227.  
  228. /* types MIME */
  229. const char hts_mime[][2][32] = {
  230.   {"application/acad","dwg"},
  231.   {"application/arj","arj"},
  232.   {"application/clariscad","ccad"},
  233.   {"application/drafting","drw"},
  234.   {"application/dxf","dxf"},
  235.   {"application/excel","xls"},
  236.   {"application/i-deas","unv"},
  237.   {"application/iges","isg"},
  238.   {"application/iges","iges"},
  239.   {"application/mac-binhex40","hqx"},
  240.   {"application/mac-compactpro","cpt"},
  241.   {"application/msword","doc"},
  242.   {"application/msword","w6w"},
  243.   {"application/msword","word"},
  244.   {"application/mswrite","wri"},
  245.   /*{"application/octet-stream","dms"},*/
  246.   /*{"application/octet-stream","lzh"},*/
  247.   /*{"application/octet-stream","lha"},*/
  248.   /*{"application/octet-stream","bin"},*/
  249.   {"application/oda","oda"},
  250.   {"application/pdf","pdf"},
  251.   {"application/postscript","ps"},
  252.   {"application/postscript","ai"},
  253.   {"application/postscript","eps"},
  254.   {"application/powerpoint","ppt"},
  255.   {"application/pro_eng","prt"},
  256.   {"application/pro_eng","part"},
  257.   {"application/rtf","rtf"},
  258.   {"application/set","set"},
  259.   {"application/sla","stl"},
  260.   {"application/smil","smi"},
  261.   {"application/smil","smil"},
  262.   {"application/smil","sml"},
  263.   {"application/solids","sol"},
  264.   {"application/STEP","stp"},
  265.   {"application/STEP","step"},
  266.   {"application/vda","vda"},
  267.   {"application/x-authorware-map","aam"},     
  268.   {"application/x-authorware-seg","aas"},
  269.   {"application/x-authorware-bin","aab"},
  270.   {"application/x-cocoa","cco"},
  271.   {"application/x-csh","csh"},
  272.   {"application/x-director","dir"},
  273.   {"application/x-director","dcr"},
  274.   {"application/x-director","dxr"},
  275.   {"application/x-mif","mif"},
  276.   {"application/x-dvi","dvi"},
  277.   {"application/x-gzip","gz"},
  278.   {"application/x-gzip","gzip"},
  279.   {"application/x-hdf","hdf"},
  280.   {"application/x-javascript","js"},
  281.   {"application/x-koan","skp"},
  282.   {"application/x-koan","skd"},
  283.   {"application/x-koan","skt"},
  284.   {"application/x-koan","skm"},
  285.   {"application/x-latex","latex"},
  286.   {"application/x-netcdf","nc"},
  287.   {"application/x-netcdf","cdf"},
  288.   /* {"application/x-sh","sh"}, */
  289.   /* {"application/x-csh","csh"}, */
  290.   /* {"application/x-ksh","ksh"}, */
  291.   {"application/x-shar","shar"},
  292.   {"application/x-stuffit","sit"},
  293.   {"application/x-tcl","tcl"},
  294.   {"application/x-tex","tex"},
  295.   {"application/x-texinfo","texinfo"},
  296.   {"application/x-texinfo","texi"},
  297.   {"application/x-troff","t"},
  298.   {"application/x-troff","tr"},
  299.   {"application/x-troff","roff"},
  300.   {"application/x-troff-man","man"},
  301.   {"application/x-troff-me","ms"},
  302.   {"application/x-wais-source","src"},
  303.   {"application/zip","zip"},
  304.   {"application/x-zip-compressed","zip"},
  305.   {"application/x-bcpio","bcpio"},
  306.   {"application/x-cdlink","vcd"},
  307.   {"application/x-cpio","cpio"},
  308.   {"application/x-gtar","tgz"},
  309.   {"application/x-gtar","gtar"},
  310.   {"application/x-shar","shar"},
  311.   {"application/x-shockwave-flash","swf"},
  312.   {"application/x-sv4cpio","sv4cpio"},
  313.   {"application/x-sv4crc","sv4crc"},
  314.   {"application/x-tar","tar"},
  315.   {"application/x-ustar","ustar"},
  316.   {"application/x-winhelp","hlp"},
  317.   {"audio/midi","mid"},
  318.   {"audio/midi","midi"},
  319.   {"audio/midi","kar"},
  320.   {"audio/mpeg","mp3"},
  321.   {"audio/mpeg","mpga"},
  322.   {"audio/mpeg","mp2"},
  323.   {"audio/basic","au"},
  324.   {"audio/basic","snd"},
  325.   {"audio/x-aiff","aif"},
  326.   {"audio/x-aiff","aiff"},
  327.   {"audio/x-aiff","aifc"},
  328.   {"audio/x-pn-realaudio","rm"},
  329.   {"audio/x-pn-realaudio","ram"},
  330.   {"audio/x-pn-realaudio","ra"},
  331.   {"audio/x-pn-realaudio-plugin","rpm"},
  332.   {"audio/x-wav","wav"},
  333.   {"chemical/x-pdb","pdb"},
  334.   {"chemical/x-pdb","xyz"},
  335.   {"drawing/x-dwf","dwf"},
  336.   {"image/gif","gif"},
  337.   {"image/ief","ief"},
  338.   {"image/jpeg","jpg"},
  339.   {"image/jpeg","jpe"},
  340.   {"image/jpeg","jpeg"},
  341.   {"image/pict","pict"},
  342.   {"image/png","png"},
  343.   {"image/tiff","tiff"},
  344.   {"image/tiff","tif"},
  345.   {"image/svg+xml","svg"},
  346.   {"image/svg-xml","svg"},
  347.   {"image/x-cmu-raster","ras"},
  348.   {"image/x-freehand","fh4"},
  349.   {"image/x-freehand","fh7"},
  350.   {"image/x-freehand","fh5"},  
  351.   {"image/x-freehand","fhc"},
  352.   {"image/x-freehand","fh"},   
  353.   {"image/x-portable-anymap","pnm"},
  354.   {"image/x-portable-bitmap","pgm"},
  355.   {"image/x-portable-pixmap","ppm"},
  356.   {"image/x-rgb","rgb"},
  357.   {"image/x-xbitmap","xbm"},
  358.   {"image/x-xpixmap","xpm"},
  359.   {"image/x-xwindowdump","xwd"},
  360.   {"model/mesh","msh"},  
  361.   {"model/mesh","mesh"},  
  362.   {"model/mesh","silo"},  
  363.   {"multipart/x-zip","zip"},
  364.   {"multipart/x-gzip","gzip"},
  365.   {"text/css","css"},
  366.   {"text/html","html"},
  367.   {"text/html","htm"},
  368.   {"text/plain","txt"},
  369.   {"text/plain","g"},
  370.   {"text/plain","h"},
  371.   {"text/plain","c"},
  372.   {"text/plain","cc"},
  373.   {"text/plain","hh"},
  374.   {"text/plain","m"},
  375.   {"text/plain","f90"},
  376.   {"text/richtext","rtx"},
  377.   {"text/tab-separated-values","tsv"},
  378.   {"text/x-setext","etx"},
  379.   {"text/x-sgml","sgml"},
  380.   {"text/x-sgml","sgm"},
  381.   {"text/xml","xml"},  
  382.   {"text/xml","dtd"},  
  383.   {"video/mpeg","mpeg"},
  384.   {"video/mpeg","mpg"},
  385.   {"video/mpeg","mpe"},
  386.   {"video/quicktime","qt"},
  387.   {"video/quicktime","mov"},
  388.   {"video/x-msvideo","avi"},
  389.   {"video/x-sgi-movie","movie"},
  390.   {"x-conference/x-cooltalk","ice"},
  391.   /*{"application/x-httpd-cgi","cgi"},*/
  392.   {"x-world/x-vrml","wrl"},
  393.   
  394.   {"*","class"},
  395.   
  396.   {"",""}};
  397.  
  398.  
  399. // Reserved (RFC2396)
  400. #define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  401. // Delimiters (RFC2396)
  402. #define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  403. // Unwise (RFC2396)
  404. #define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  405. // Special (escape chars) (RFC2396 + >127 )
  406. #define CHAR_LOW(c)       ( ((unsigned char)(c) <= 31) )
  407. #define CHAR_HIG(c)       ( ((unsigned char)(c) >= 127) )
  408. #define CHAR_SPECIAL(c)   ( CHAR_LOW(c) || CHAR_HIG(c) )
  409. // We try to avoid them and encode them instead
  410. #define CHAR_XXAVOID(c)   ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
  411.  
  412.  
  413. // conversion Θventuelle / vers antislash
  414. #if HTS_WIN
  415. char* antislash(char* s) {
  416.   char* buff;
  417.   char* a;
  418.   NOSTATIC_RESERVE(buff, char, HTS_URLMAXSIZE*2);
  419.  
  420.   strcpybuff(buff,s);
  421.   while(a=strchr(buff,'/')) *a='\\';
  422.   return buff;
  423. }
  424. #endif
  425.  
  426.  
  427.  
  428. // RΘcupΘration d'un fichier http sur le net.
  429. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  430. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  431. //
  432. // Une adresse de structure htsmsg peut Ωtre transmise pour
  433. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  434. // en background
  435.  
  436. htsblk httpget(char* url) {
  437.   char adr[HTS_URLMAXSIZE*2];   // adresse
  438.   char fil[HTS_URLMAXSIZE*2];   // chemin
  439.   
  440.   // sΘparer URL en adresse+chemin
  441.   if (ident_url_absolute(url,adr,fil)==-1) {
  442.     htsblk retour;
  443.     memset(&retour, 0, sizeof(htsblk));    // effacer
  444.     // retour prΘdΘfini: erreur
  445.     retour.adr=NULL;
  446.     retour.size=0;
  447.     retour.msg[0]='\0';
  448.     retour.statuscode=-1;    
  449.     strcpybuff(retour.msg,"Error invalid URL");
  450.     return retour;
  451.   }
  452.   
  453.   return xhttpget(adr,fil);
  454. }
  455.  
  456. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  457. // retour: socket
  458. int http_fopen(char* adr,char* fil,htsblk* retour) {
  459.   //                / GET, traiter en-tΩte
  460.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  461. }
  462.  
  463. // ouverture d'une liaison http, envoi d'une requΦte
  464. // mode: 0 GET  1 HEAD  [2 POST]
  465. // treat: traiter header?
  466. // waitconnect: attendre le connect()
  467. // note: dans retour, on met les params du proxy
  468. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  469.   //htsblk retour;
  470.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  471.   T_SOC soc=INVALID_SOCKET;
  472.   //char *p,*q;
  473.   
  474.   // retour prΘdΘfini: erreur
  475.   if (retour) {
  476.     retour->adr=NULL;
  477.     retour->size=0;
  478.     retour->msg[0]='\0';
  479.     retour->statuscode=-5;          // a priori erreur non fatale
  480.   }
  481.  
  482. #if HDEBUG
  483.   printf("adr=%s\nfichier=%s\n",adr,fil);
  484. #endif
  485.   
  486.   // ouvrir liaison
  487. #if HDEBUG
  488.   printf("CrΘation d'une socket sur %s\n",adr);
  489. #endif
  490.  
  491. #if CNXDEBUG
  492.   printf("..newhttp\n");
  493. #endif
  494.  
  495.   /* connexion */
  496.   if (retour) {
  497.     if ( (!(retour->req.proxy.active)) 
  498.       ||
  499.       (
  500.         (strcmp(adr,"file://")==0) 
  501.         ||
  502.         (strncmp(adr,"https://", 8)==0) 
  503.       )
  504.       ) {    /* pas de proxy, ou non utilisable ici */
  505.       soc=newhttp(adr,retour,-1,waitconnect);
  506.     } else {
  507.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  508.     }
  509.   } else {
  510.     soc=newhttp(adr,NULL,-1,waitconnect);    
  511.   }
  512.  
  513.   // copier index socket retour
  514.   if (retour) retour->soc=soc;
  515.  
  516.   /* Check for errors */
  517.   if (soc == INVALID_SOCKET) {
  518.     if (retour) {
  519.       if (retour->msg) {
  520.         if (!strnotempty(retour->msg)) {
  521.           strcpybuff(retour->msg,"Connect error");
  522.         }
  523.       }
  524.     }
  525.   }
  526.  
  527.   // --------------------
  528.   // court-circuit (court circuite aussi le proxy..)
  529.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  530.   if (soc==LOCAL_SOCKET_ID) {
  531.     retour->is_file=1;  // fichier local
  532.     if (mode==0) {    // GET
  533.  
  534.       // Test en cas de file:///C|...
  535.       if (!fexist(fconv(unescape_http(fil))))
  536.         if (fexist(fconv(unescape_http(fil+1)))) {
  537.           char tempo[HTS_URLMAXSIZE*2];
  538.           strcpybuff(tempo,fil+1);
  539.           strcpybuff(fil,tempo);
  540.         }
  541.  
  542.       // Ouvrir
  543.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  544.       retour->msg[0]='\0';
  545.       soc=INVALID_SOCKET;
  546.       if (retour->totalsize<0)
  547.         strcpybuff(retour->msg,"Unable to open file");
  548.       else if (retour->totalsize==0)
  549.         strcpybuff(retour->msg,"File empty");
  550.       else {
  551.         // Note: On passe par un FILE* (plus propre)
  552.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  553.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  554.         if (retour->fp==NULL)
  555.           soc=INVALID_SOCKET;
  556.         else
  557.           soc=LOCAL_SOCKET_ID;
  558.       }
  559.       retour->soc=soc;
  560.       if (soc!=INVALID_SOCKET) {
  561.         retour->statuscode=200;   // OK
  562.         strcpybuff(retour->msg,"OK");
  563.         guess_httptype(retour->contenttype,fil);
  564.       } else if (strnotempty(retour->msg)==0)
  565.           strcpybuff(retour->msg,"Unable to open file");
  566.       return soc;  // renvoyer
  567.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  568.       strcpybuff(retour->msg,"Unexpected Head/Post local request");
  569.       soc=INVALID_SOCKET;    // erreur
  570.       retour->soc=soc;
  571.       return soc;
  572.     }
  573.   } 
  574.   // --------------------
  575.  
  576.   if (soc!=INVALID_SOCKET) {    
  577.     char rcvd[1100];
  578.     rcvd[0]='\0';
  579. #if HDEBUG
  580.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  581. #endif
  582.     
  583.     // connectΘ?
  584.     if (waitconnect) {
  585.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  586.     } 
  587.     
  588.     if (soc!=INVALID_SOCKET) {
  589.       
  590. #if HDEBUG
  591.       printf("Attente de la rΘponse:\n");
  592. #endif
  593.       
  594.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  595.       // et ensuite le corps
  596.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  597.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  598.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  599.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  600.         
  601.         // status-line α rΘcupΘrer
  602.         finput(soc,rcvd,1024);
  603.         if (strnotempty(rcvd)==0)
  604.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  605.  
  606.         // traiter status-line
  607.         treatfirstline(retour,rcvd);
  608.  
  609. #if HDEBUG
  610.         printf("Status-Code=%d\n",retour->statuscode);
  611. #endif
  612.         
  613.         // en-tΩte
  614.         
  615.         // header // ** !attention! HTTP/0.9 non supportΘ
  616.         do {
  617.           finput(soc,rcvd,1024);          
  618. #if HDEBUG
  619.           printf(">%s\n",rcvd);      
  620. #endif
  621.           if (strnotempty(rcvd))
  622.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  623.  
  624.         } while(strnotempty(rcvd));
  625.         
  626.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  627.         
  628.         //if (retour)
  629.         //  retour->totalsize=rcvsize;
  630.         
  631.       } else { // si GET, on recevra l'en tΩte APRES
  632.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  633.         if (retour)
  634.           retour->totalsize=-1;
  635.       }
  636.       
  637.     }
  638.  
  639.   }
  640.     
  641.   return soc;
  642. }
  643.  
  644.  
  645. // envoi d'une requΦte
  646. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  647.   char buff[8192];
  648.   //int use_11=0;     // HTTP 1.1 utilisΘ
  649.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  650.   char* search_tag=NULL;
  651.   buff[0]='\0';
  652.  
  653.   // header Date
  654.   //strcatbuff(buff,"Date: ");
  655.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  656.   //sendc("\n");
  657.   //strcatbuff(buff,buff);
  658.  
  659.   // possibilitΘ non documentΘe: >post: et >postfile:
  660.   // si prΘsence d'un tag >post: alors executer un POST
  661.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  662.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  663.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  664.   search_tag=strstr(fil,POSTTOK":");
  665.   if (!search_tag) {
  666.     search_tag=strstr(fil,POSTTOK"file:");
  667.     if (search_tag) {     // postfile
  668.       if (mode==0) {      // GET!
  669.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  670.         if (fp) {
  671.           char line[1100];
  672.           char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  673.           linput(fp,line,1000);
  674.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  675.             // selon que l'on a ou pas un proxy
  676.             if (retour->req.proxy.active)
  677.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  678.             else
  679.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  680.             // lire le reste en brut
  681.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  682.           }
  683.           fclose(fp);
  684.         }
  685.       }
  686.     }
  687.   }
  688.   // Fin postfile
  689.   
  690.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  691.     // Type de requΦte?
  692.     if ((search_tag) && (mode==0)) {
  693.       strcatbuff(buff,"POST ");
  694.     } else if (mode==0) {    // GET
  695.       strcatbuff(buff,"GET ");
  696.     } else {  // if (mode==1) {
  697.       if (!retour->req.http11)        // forcer HTTP/1.0
  698.         strcatbuff(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  699.       else
  700.         strcatbuff(buff,"HEAD ");
  701.     }
  702.     
  703.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  704.     if ( retour->req.proxy.active && (strncmp(adr,"https://", 8) != 0) ) {
  705.       if (!link_has_authority(adr)) {  // default http
  706. #if HDEBUG
  707.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  708. #endif
  709.         strcatbuff(buff,"http://");
  710.         strcatbuff(buff,jump_identification(adr));
  711.       } else {          // ftp:// en proxy http
  712. #if HDEBUG
  713.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  714. #endif
  715.         direct_url=1;             // ne pas analyser user/pass
  716.         strcatbuff(buff,adr);
  717.       }
  718.     } 
  719.     
  720.     // NOM DU FICHIER
  721.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  722.     if (*fil!='/') strcatbuff(buff,"/");
  723.     {
  724.       char tempo[HTS_URLMAXSIZE*2];
  725.       tempo[0]='\0';
  726.       if (search_tag)
  727.         strncatbuff(tempo,fil,(int) (search_tag - fil));
  728.       else
  729.         strcpybuff(tempo,fil);
  730.       escape_check_url(tempo);
  731.       strcatbuff(buff,tempo);       // avec Θchappement
  732.     }
  733.     
  734.     // protocole
  735.     if (!retour->req.http11) {     // forcer HTTP/1.0
  736.       //use_11=0;
  737.       strcatbuff(buff," HTTP/1.0\x0d\x0a");
  738.     } else {                   // RequΦte 1.1
  739.       //use_11=1;
  740.       strcatbuff(buff," HTTP/1.1\x0d\x0a");
  741.     }
  742.  
  743.     /* supplemental data */
  744.     if (xsend) strcatbuff(buff,xsend);    // Θventuelles autres lignes
  745.  
  746.     // tester proxy authentication
  747.     if (retour->req.proxy.active) {
  748.       if (link_has_authorization(retour->req.proxy.name)) {  // et hop, authentification proxy!
  749.         char* a=jump_identification(retour->req.proxy.name);
  750.         char* astart=jump_protocol(retour->req.proxy.name);
  751.         char autorisation[1100];
  752.         char user_pass[256];        
  753.         autorisation[0]=user_pass[0]='\0';
  754.         //
  755.         strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  756.         strcpybuff(user_pass,unescape_http(user_pass));
  757.         code64(user_pass,autorisation);
  758.         strcatbuff(buff,"Proxy-Authorization: Basic ");
  759.         strcatbuff(buff,autorisation);
  760.         strcatbuff(buff,H_CRLF);
  761. #if HDEBUG
  762.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  763. #endif
  764.       }
  765.     }
  766.     
  767.     // Referer?
  768.     if ((referer_adr) && (referer_fil)) {       // existe
  769.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  770.         if (
  771.           (strcmp(referer_adr,"file://") != 0)
  772.           &&
  773.           (  /* no https referer to http urls */
  774.             (strncmp(referer_adr, "https://", 8) != 0)  /* referer is not https */
  775.             ||
  776.             (strncmp(adr, "https://", 8) == 0)          /* or referer AND addresses are https */
  777.           )
  778.           ) {      // PAS file://
  779.           strcatbuff(buff,"Referer: ");
  780.           strcatbuff(buff,"http://");
  781.           strcatbuff(buff,jump_identification(referer_adr));
  782.           strcatbuff(buff,referer_fil);
  783.           strcatbuff(buff,H_CRLF);
  784.         }
  785.       }
  786.     }
  787.     
  788.     // POST?
  789.     if (mode==0) {      // GET!
  790.       if (search_tag) {
  791.         char clen[256];
  792.         sprintf(clen,"Content-length: %d"H_CRLF,(int)(strlen(unescape_http(search_tag+strlen(POSTTOK)+1))));
  793.         strcatbuff(buff,clen);
  794.       }
  795.     }
  796.     
  797.     // gestion cookies?
  798.     if (cookie) {
  799.       char* b=cookie->data;
  800.       int cook=0;
  801.       int max_cookies=8;
  802.       int max_size=2048;
  803.       max_size+=strlen(buff);
  804.       do {
  805.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  806.         if (b) {
  807.           max_cookies--;
  808.           if (!cook) {
  809.             strcatbuff(buff,"Cookie: ");
  810.             strcatbuff(buff,"$Version=1; ");
  811.             cook=1;
  812.           } else
  813.             strcatbuff(buff,"; ");
  814.           strcatbuff(buff,cookie_get(b,5));
  815.           strcatbuff(buff,"=");
  816.           strcatbuff(buff,cookie_get(b,6));
  817.           strcatbuff(buff,"; $Path=");
  818.           strcatbuff(buff,cookie_get(b,2));
  819.           b=cookie_nextfield(b);
  820.         }
  821.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  822.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  823.         strcatbuff(buff,H_CRLF);
  824. #if DEBUG_COOK
  825.         printf("Header:\n%s\n",buff);
  826. #endif
  827.       }
  828.     }
  829.     
  830.     // gΘrer le keep-alive (garder socket)
  831.     if (retour->req.http11 && !retour->req.nokeepalive) {
  832.             strcatbuff(buff,"Connection: Keep-Alive"H_CRLF);
  833.         } else {
  834.       strcatbuff(buff,"Connection: close"H_CRLF);
  835.         }
  836.     
  837.     {
  838.       char* real_adr=jump_identification(adr);
  839.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  840.       if (!direct_url) {     // pas ftp:// par exemple
  841.         //if (!retour->req.proxy.active) {
  842.         strcatbuff(buff,"Host: "); strcatbuff(buff,real_adr); strcatbuff(buff,H_CRLF);
  843.         //}
  844.       }
  845.       //}
  846.  
  847.       // PrΘsence d'un user-agent?
  848.       if (retour->req.user_agent_send) {  // ohh un user-agent
  849.         char s[256];
  850.         // HyperTextSeeker/"HTSVERSION
  851.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  852.         strcatbuff(buff,s);
  853.         
  854.         // pour les serveurs difficiles
  855.         strcatbuff(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/svg+xml, */*"H_CRLF);
  856.         if (strnotempty(retour->req.lang_iso)) {
  857.           strcatbuff(buff,"Accept-Language: "); strcatbuff(buff,retour->req.lang_iso); strcatbuff(buff,H_CRLF);
  858.         }
  859.         strcatbuff(buff,"Accept-Charset: iso-8859-1, iso-8859-*, utf-8"H_CRLF);   
  860.         if (retour->req.http11) {
  861. #if HTS_USEZLIB
  862.           if (gz_is_available && (!retour->req.range_used) && (!retour->req.nocompression))
  863.             strcatbuff(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF);
  864.           else
  865.             strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);       /* no compression */
  866. #else
  867.           strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  868. #endif
  869.         }
  870.       } else {
  871.         strcatbuff(buff,"Accept: */*"H_CRLF);         // le minimum
  872.       }
  873.  
  874.       /* Authentification */
  875.       {
  876.         char autorisation[1100];
  877.         char* a;
  878.         autorisation[0]='\0';
  879.         if (link_has_authorization(adr)) {  // ohh une authentification!
  880.           char* a=jump_identification(adr);
  881.           char* astart=jump_protocol(adr);
  882.           if (!direct_url) {      // pas ftp:// par exemple
  883.             char user_pass[256];
  884.             user_pass[0]='\0';
  885.             strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  886.             strcpybuff(user_pass,unescape_http(user_pass));
  887.             code64(user_pass,autorisation);
  888.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  889.               bauth_add(cookie,astart,fil,autorisation);
  890.           }
  891.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  892.           strcpybuff(autorisation,a);
  893.         /* On a une autorisation a donner?  */
  894.         if (strnotempty(autorisation)) {
  895.           strcatbuff(buff,"Authorization: Basic ");
  896.           strcatbuff(buff,autorisation);
  897.           strcatbuff(buff,H_CRLF);
  898.         }
  899.       }
  900.  
  901.     }
  902.     //strcatbuff(buff,"Accept-Language: en\n");
  903.     //strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  904.     
  905.     // CRLF de fin d'en tΩte
  906.     strcatbuff(buff,H_CRLF);
  907.     
  908.     // donnΘes complΘmentaires?
  909.     if (search_tag)
  910.     if (mode==0)      // GET!
  911.       strcatbuff(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  912.   }
  913.   
  914. #if HDEBUG
  915. #endif
  916.   if (_DEBUG_HEAD) {
  917.     if (ioinfo) {
  918.       fprintf(ioinfo,"[%d] request for %s%s:\r\n",retour->debugid,jump_identification(adr),fil);
  919.       fprintfio(ioinfo,buff,"<<< ");
  920.       fprintf(ioinfo,"\r\n");
  921.       fflush(ioinfo);
  922.     }
  923.   }  // Fin test pas postfile
  924.   //
  925.  
  926.   // Envoi
  927.   if (sendc(retour, buff)<0) {  // ERREUR, socket rompue?...
  928.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  929.     deletesoc_r(retour);  // fermer tout de mΩme
  930.     // et tenter de reconnecter
  931.     
  932.     strcpybuff(retour->msg,"Broken pipe");
  933.     retour->soc=INVALID_SOCKET;
  934.   }
  935.   
  936.   // RX'98
  937.   return 0;
  938. }
  939.  
  940.  
  941.  
  942.  
  943. // traiter 1ere ligne d'en tΩte
  944. void treatfirstline(htsblk* retour,char* rcvd) {
  945.   char* a=rcvd;
  946.   // exemple:
  947.   // HTTP/1.0 200 OK
  948.   if (*a) {
  949.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  950.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  951.     if (strfield(a, "HTTP/")) {
  952.       // sauter HTTP/1.x
  953.       while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  954.       if (*a != '\0') {
  955.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  956.         if ((*a>='0') && (*a<='9')) {
  957.           sscanf(a,"%d",&(retour->statuscode));
  958.           // sauter 200
  959.           while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  960.           while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  961.           if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  962.             strcpybuff(retour->msg,a);
  963.           else
  964.             infostatuscode(retour->msg,retour->statuscode);
  965.           // type MIME par dΘfaut2
  966.           strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  967.         } else {  // pas de code!
  968.           retour->statuscode=-1;
  969.           strcpybuff(retour->msg,"Unknown response structure");
  970.         }
  971.       } else {  // euhh??
  972.         retour->statuscode=-1;
  973.         strcpybuff(retour->msg,"Unknown response structure");
  974.       }
  975.     } else {
  976.             if (*a == '<') {
  977.         /* This is dirty .. */
  978.         retour->statuscode=200;
  979.         retour->keep_alive=0;
  980.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  981.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  982.             } else if (strnotempty(a)) {
  983.         retour->statuscode=-1;
  984.         strcpybuff(retour->msg,"Unknown (not HTTP/xx) response structure");
  985.       } else {
  986.         /* This is dirty .. */
  987.         retour->statuscode=200;
  988.         retour->keep_alive=0;
  989.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  990.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  991.       }
  992.     }
  993.   } else {  // vide!
  994.     /*
  995.     retour->statuscode=-1;
  996.     strcpybuff(retour->msg,"Empty reponse or internal error");
  997.     */
  998.     /* This is dirty .. */
  999.     retour->statuscode=200;
  1000.     strcpybuff(retour->msg, "Unknown, assuming junky server");
  1001.     strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1002.   }
  1003. }
  1004.  
  1005. // traiter ligne par ligne l'en tΩte
  1006. // gestion des cookies
  1007. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  1008.   int p;
  1009.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  1010. #if HDEBUG
  1011.     printf("ok, Content-length: dΘtectΘ\n");
  1012. #endif
  1013.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  1014.     if (retour->totalsize == 0) {
  1015.       retour->empty = 1;
  1016.     }
  1017.   }
  1018.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  1019.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  1020.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  1021.       char tmp[256];
  1022.       char *a=NULL,*b=NULL;
  1023.       strcpybuff(tmp,rcvd+p);
  1024.       a=strstr(tmp,"filename=");
  1025.       if (a) {
  1026.         a+=strlen("filename=");
  1027.         while(is_space(*a)) a++;
  1028.         //a=strchr(a,'"');
  1029.         if (a) {
  1030.           char *c=NULL;
  1031.           //a++;      /* jump " */
  1032.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  1033.             a=c+1;
  1034.           //b=strchr(a+1,'"');
  1035.           b=a+strlen(a)-1;
  1036.           while(is_space(*b)) b--;
  1037.           b++;
  1038.           if (b) {
  1039.             *b='\0';
  1040.             if ((int) strlen(a) < 200) { // pas trop long?
  1041.               strcpybuff(retour->cdispo,a);
  1042.             }
  1043.           }
  1044.         }
  1045.       } 
  1046.     }
  1047.   }
  1048.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  1049.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  1050.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1051.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1052.       strcpybuff(retour->lastmodified,rcvd+p);
  1053.     }
  1054.   }
  1055.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  1056.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  1057.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  1058.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1059.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1060.         strcpybuff(retour->lastmodified,rcvd+p);
  1061.       }
  1062.     }
  1063.   }
  1064.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  1065.     if (retour) {
  1066.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  1067.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  1068.         strcpybuff(retour->etag,rcvd+p);
  1069.       else    // erreur.. ignorer
  1070.         retour->etag[0]='\0';
  1071.     }
  1072.   }
  1073.   else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  1074.     retour->is_chunk=1;     // chunked
  1075.     //retour->http11=2;     // chunked
  1076. #if HDEBUG
  1077.     printf("ok, Transfer-Encoding: dΘtectΘ\n");
  1078. #endif
  1079.   }
  1080.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  1081.     if (retour) {
  1082.       char tempo[1100];
  1083.       // Θviter les text/html; charset=foo
  1084.       {
  1085.         char* a=strchr(rcvd+p,';');
  1086.         if (a) *a='\0';
  1087.       }
  1088.       sscanf(rcvd+p,"%s",tempo);
  1089.       if (strlen(tempo)<64)    // pas trop long!!
  1090.         strcpybuff(retour->contenttype,tempo);
  1091.       else
  1092.         strcpybuff(retour->contenttype,"application/octet-stream-unknown");    // erreur
  1093.     }
  1094.   }
  1095.   else if ((p=strfield(rcvd,"Content-Range:"))!=0) {
  1096.     char* a=strstr(rcvd+p,"*/");
  1097.     if (a) {
  1098.       if (sscanf(a+2,LLintP,&retour->crange) != 1) {
  1099.         retour->crange=0;
  1100.       }
  1101.     }
  1102.   }
  1103.   else if ((p=strfield(rcvd,"Connection:"))!=0) {
  1104.         char* a = rcvd + p;
  1105.         while(is_space(*a)) a++;
  1106.         if (*a) {
  1107.             if (strfield(a, "Keep-Alive")) {
  1108.         if (!retour->keep_alive) {
  1109.           retour->keep_alive_max = 10;
  1110.           retour->keep_alive_t = 15;
  1111.         }
  1112.         retour->keep_alive = 1;
  1113.       } else {
  1114.                 retour->keep_alive = 0;
  1115.       }
  1116.         }
  1117.     }
  1118.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {
  1119.         char* a = rcvd + p;
  1120.         while(is_space(*a)) a++;
  1121.         if (*a) {
  1122.       char* p;
  1123.       retour->keep_alive = 1;
  1124.       retour->keep_alive_max = 10;
  1125.       retour->keep_alive_t = 15;
  1126.       if ((p=strstr(a, "timeout="))) {
  1127.         p+=strlen("timeout=");
  1128.         sscanf(p, "%d", &retour->keep_alive_t);
  1129.       }
  1130.       if ((p=strstr(a, "max="))) {
  1131.         p+=strlen("max=");
  1132.         sscanf(p, "%d", &retour->keep_alive_max);
  1133.       }
  1134.       if (retour->keep_alive_max <= 1 || retour->keep_alive_t < 3) {
  1135.         retour->keep_alive = 0;
  1136.       }
  1137.     }
  1138.   }
  1139.   else if ((p=strfield(rcvd,"TE:"))!=0) {
  1140.         char* a = rcvd + p;
  1141.         while(is_space(*a)) a++;
  1142.         if (*a) {
  1143.       if (strfield(a, "trailers")) {
  1144.         retour->keep_alive_trailers=1;
  1145.       }
  1146.     }
  1147.   }
  1148.     else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) {
  1149.         if (retour) {
  1150.             char tempo[1100];
  1151.             {
  1152.                 char* a=strchr(rcvd+p,';');
  1153.                 if (a) *a='\0';
  1154.             }
  1155.             sscanf(rcvd+p,"%s",tempo);
  1156.       if (strlen(tempo)<64)    // pas trop long!!
  1157.         strcpybuff(retour->contentencoding,tempo);
  1158.       else
  1159.         retour->contentencoding[0]='\0';    // erreur
  1160. #if HTS_USEZLIB
  1161.       /* Check known encodings */
  1162.       if (retour->contentencoding[0]) {
  1163.         if (
  1164.           (strfield2(retour->contentencoding, "gzip"))
  1165.           || (strfield2(retour->contentencoding, "x-gzip"))
  1166.           /*
  1167.           || (strfield2(retour->contentencoding, "compress"))
  1168.           || (strfield2(retour->contentencoding, "x-compress"))
  1169.           */
  1170.           || (strfield2(retour->contentencoding, "deflate"))
  1171.           || (strfield2(retour->contentencoding, "x-deflate"))
  1172.           ) {
  1173.         retour->compressed=1;
  1174.         }
  1175.       }
  1176. #endif
  1177.     }
  1178.   }
  1179.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  1180.     if (retour) {
  1181.       if (retour->location) {
  1182.         while(*(rcvd+p)==' ') p++;    // sauter espaces
  1183.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  1184.           strcpybuff(retour->location,rcvd+p);
  1185.         else    // erreur.. ignorer
  1186.           retour->location[0]='\0';
  1187.       }
  1188.     }
  1189.   }
  1190.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  1191.     char* a = rcvd+p;           // pointeur
  1192.     char domain[256];           // domaine cookie (.netscape.com)
  1193.     char path[256];             // chemin (/)
  1194.     char cook_name[256];        // nom cookie (MYCOOK)
  1195.     char cook_value[8192];      // valeur (ID=toto,S=1234)
  1196. #if DEBUG_COOK
  1197.     printf("set-cookie detected\n");
  1198. #endif
  1199.     while(*a) {
  1200.       char *token_st,*token_end;
  1201.       char *value_st,*value_end;
  1202.       char name[256];
  1203.       char value[8192];
  1204.       int next=0;
  1205.       name[0]=value[0]='\0';
  1206.       //
  1207.  
  1208.       // initialiser cookie lu actuellement
  1209.       if (adr)
  1210.         strcpybuff(domain,jump_identification(adr));     // domaine
  1211.       strcpybuff(path,"/");         // chemin (/)
  1212.       strcpybuff(cook_name,"");     // nom cookie (MYCOOK)
  1213.       strcpybuff(cook_value,"");    // valeur (ID=toto,S=1234)
  1214.       // boucler jusqu'au prochain cookie ou la fin
  1215.       do {
  1216.         char* start_loop=a;
  1217.         while(is_space(*a)) a++;    // sauter espaces
  1218.         token_st=a;                 // dΘpart token
  1219.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1220.         token_end=a;
  1221.         while(is_space(*a)) a++;    // sauter espaces
  1222.         if (*a=='=') {    // name=value
  1223.           a++;
  1224.           while(is_space(*a)) a++;    // sauter espaces
  1225.           value_st=a;
  1226.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1227.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1228.           value_end=a;
  1229.           //if (*a==';') {  // finit par un ;
  1230.           // vΘrifier dΘbordements
  1231.           if ( (((int) (token_end - token_st))<200) && (((int) (value_end - value_st))<8000)
  1232.             && (((int) (token_end - token_st))>0)   && (((int) (value_end - value_st))>0) ) {
  1233.             name[0]='\0';
  1234.             value[0]='\0';
  1235.             strncatbuff(name,token_st,(int) (token_end - token_st));
  1236.             strncatbuff(value,value_st,(int) (value_end - value_st));
  1237. #if DEBUG_COOK
  1238.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1239. #endif
  1240.             if (strfield2(name,"domain")) {
  1241.               strcpybuff(domain,value);
  1242.             }
  1243.             else if (strfield2(name,"path")) {
  1244.               strcpybuff(path,value);
  1245.             }
  1246.             else if (strfield2(name,"max-age")) {
  1247.               // ignorΘ..
  1248.             }
  1249.             else if (strfield2(name,"expires")) {
  1250.               // ignorΘ..
  1251.             }
  1252.             else if (strfield2(name,"version")) {
  1253.               // ignorΘ..
  1254.             }
  1255.             else if (strfield2(name,"comment")) {
  1256.               // ignorΘ
  1257.             }
  1258.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1259.               // ignorΘ
  1260.             }
  1261.             else {
  1262.               if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1263.                 strcpybuff(cook_name,name);
  1264.                 strcpybuff(cook_value,value);
  1265.               } else {                             // prochain cookie
  1266.                 a=start_loop;      // on devra recommencer α cette position
  1267.                 next=1;            // enregistrer
  1268.               }
  1269.             }
  1270.           }
  1271.         }
  1272.         if (!next) {
  1273.           while((*a!=';') && (*a)) a++;    // prochain
  1274.           while(*a==';') a++;             // sauter ;
  1275.         }
  1276.       } while((*a) && (!next));
  1277.       if (strnotempty(cook_name)) {          // cookie?
  1278. #if DEBUG_COOK
  1279.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1280. #endif
  1281.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1282.       }
  1283.     }
  1284.   }
  1285. }
  1286.  
  1287.  
  1288. // transforme le message statuscode en chaεne
  1289. HTSEXT_API void infostatuscode(char* msg,int statuscode) {
  1290.   switch( statuscode) {    
  1291.     // Erreurs HTTP, selon RFC
  1292.   case 100: strcpybuff( msg,"Continue"); break; 
  1293.   case 101: strcpybuff( msg,"Switching Protocols"); break; 
  1294.   case 200: strcpybuff( msg,"OK"); break; 
  1295.   case 201: strcpybuff( msg,"Created"); break; 
  1296.   case 202: strcpybuff( msg,"Accepted"); break; 
  1297.   case 203: strcpybuff( msg,"Non-Authoritative Information"); break; 
  1298.   case 204: strcpybuff( msg,"No Content"); break; 
  1299.   case 205: strcpybuff( msg,"Reset Content"); break; 
  1300.   case 206: strcpybuff( msg,"Partial Content"); break; 
  1301.   case 300: strcpybuff( msg,"Multiple Choices"); break; 
  1302.   case 301: strcpybuff( msg,"Moved Permanently"); break; 
  1303.   case 302: strcpybuff( msg,"Moved Temporarily"); break; 
  1304.   case 303: strcpybuff( msg,"See Other"); break; 
  1305.   case 304: strcpybuff( msg,"Not Modified"); break; 
  1306.   case 305: strcpybuff( msg,"Use Proxy"); break; 
  1307.   case 306: strcpybuff( msg,"Undefined 306 error"); break; 
  1308.   case 307: strcpybuff( msg,"Temporary Redirect"); break; 
  1309.   case 400: strcpybuff( msg,"Bad Request"); break; 
  1310.   case 401: strcpybuff( msg,"Unauthorized"); break; 
  1311.   case 402: strcpybuff( msg,"Payment Required"); break; 
  1312.   case 403: strcpybuff( msg,"Forbidden"); break; 
  1313.   case 404: strcpybuff( msg,"Not Found"); break; 
  1314.   case 405: strcpybuff( msg,"Method Not Allowed"); break; 
  1315.   case 406: strcpybuff( msg,"Not Acceptable"); break; 
  1316.   case 407: strcpybuff( msg,"Proxy Authentication Required"); break; 
  1317.   case 408: strcpybuff( msg,"Request Time-out"); break; 
  1318.   case 409: strcpybuff( msg,"Conflict"); break; 
  1319.   case 410: strcpybuff( msg,"Gone"); break; 
  1320.   case 411: strcpybuff( msg,"Length Required"); break; 
  1321.   case 412: strcpybuff( msg,"Precondition Failed"); break; 
  1322.   case 413: strcpybuff( msg,"Request Entity Too Large"); break; 
  1323.   case 414: strcpybuff( msg,"Request-URI Too Large"); break; 
  1324.   case 415: strcpybuff( msg,"Unsupported Media Type"); break; 
  1325.   case 416: strcpybuff( msg,"Requested Range Not Satisfiable"); break; 
  1326.   case 417: strcpybuff( msg,"Expectation Failed"); break; 
  1327.   case 500: strcpybuff( msg,"Internal Server Error"); break; 
  1328.   case 501: strcpybuff( msg,"Not Implemented"); break; 
  1329.   case 502: strcpybuff( msg,"Bad Gateway"); break; 
  1330.   case 503: strcpybuff( msg,"Service Unavailable"); break; 
  1331.   case 504: strcpybuff( msg,"Gateway Time-out"); break; 
  1332.   case 505: strcpybuff( msg,"HTTP Version Not Supported"); break; 
  1333.     //
  1334.   default: if (strnotempty(msg)==0) strcpybuff( msg,"Unknown error"); break;
  1335.   }
  1336. }
  1337.  
  1338.  
  1339. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1340. htsblk xhttpget(char* adr,char* fil) {
  1341.   T_SOC soc;
  1342.   htsblk retour;
  1343.   
  1344.   memset(&retour, 0, sizeof(htsblk));
  1345.   soc=http_fopen(adr,fil,&retour);
  1346.  
  1347.   if (soc!=INVALID_SOCKET) {
  1348.     http_fread(soc,&retour);
  1349. #if HTS_DEBUG_CLOSESOCK
  1350.     DEBUG_W("xhttpget: deletehttp\n");
  1351. #endif
  1352.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1353.     retour.soc=INVALID_SOCKET;
  1354.   }
  1355.   return retour;
  1356. }
  1357.  
  1358. // variation sur un thΦme...
  1359. // rΘceptionne uniquement un en-tΩte (HEAD)
  1360. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1361. htsblk http_gethead(char* adr,char* fil) {
  1362.   T_SOC soc;
  1363.   htsblk retour;
  1364.  
  1365.   memset(&retour, 0, sizeof(htsblk));
  1366.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1367.  
  1368.   if (soc!=INVALID_SOCKET) {
  1369.     http_fread(soc,&retour);    // rΘception en-tΩte
  1370. #if HTS_DEBUG_CLOSESOCK
  1371.     DEBUG_W("http_gethead: deletehttp\n");
  1372. #endif
  1373.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1374.     retour.soc=INVALID_SOCKET;
  1375.   }
  1376.   return retour;
  1377. }
  1378. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1379.  
  1380.  
  1381. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1382. // il ne reste plus qu'α lire les donnΘes
  1383. // (pour HEAD le header est lu ici!)
  1384. void http_fread(T_SOC soc,htsblk* retour) {  
  1385.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1386.   
  1387.   if (retour) retour->soc=soc;
  1388.   if (soc!=INVALID_SOCKET) {    
  1389.     // fonction de lecture d'une socket (plus propre)
  1390.     while(http_fread1(retour)!=-1);
  1391.     soc=retour->soc;
  1392.     if (retour->adr==NULL) {
  1393.       if (strnotempty(retour->msg)==0)
  1394.         sprintf(retour->msg,"Unable to read");
  1395.       return ;    // erreur
  1396.     } 
  1397.     
  1398. #if HDEBUG
  1399.     printf("Ok, donnΘes reτues\n");
  1400. #endif   
  1401.  
  1402.     return ;
  1403.     
  1404.   } 
  1405.   
  1406.   return ;
  1407. }
  1408.  
  1409. // check if data is available
  1410. int check_readinput(htsblk* r) {
  1411.   if (r->soc != INVALID_SOCKET) {
  1412.     fd_set fds;           // poll structures
  1413.     struct timeval tv;          // structure for select
  1414.     FD_ZERO(&fds);
  1415.     FD_SET(r->soc,&fds);           
  1416.     tv.tv_sec=0;
  1417.     tv.tv_usec=0;
  1418.     select(r->soc + 1,&fds,NULL,NULL,&tv);
  1419.     if (FD_ISSET(r->soc,&fds))
  1420.       return 1;
  1421.     else
  1422.       return 0;
  1423.   } else
  1424.     return 0;
  1425. }
  1426.  
  1427. // check if data is available
  1428. int check_readinput_t(T_SOC soc, int timeout) {
  1429.   if (soc != INVALID_SOCKET) {
  1430.     fd_set fds;           // poll structures
  1431.     struct timeval tv;          // structure for select
  1432.     FD_ZERO(&fds);
  1433.     FD_SET(soc,&fds);           
  1434.     tv.tv_sec=timeout;
  1435.     tv.tv_usec=0;
  1436.     select(soc + 1,&fds,NULL,NULL,&tv);
  1437.     if (FD_ISSET(soc,&fds))
  1438.       return 1;
  1439.     else
  1440.       return 0;
  1441.   } else
  1442.     return 0;
  1443. }
  1444.  
  1445.  
  1446. // lecture d'un bloc sur une socket (ou un fichier!)
  1447. // >=0 : nombre d'octets lus
  1448. // <0 : fin ou erreur
  1449. HTS_INLINE LLint http_fread1(htsblk* r) {
  1450.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1451.   return http_xfread1(r,TAILLE_BUFFER);
  1452. }
  1453.  
  1454. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1455. // SI bufl==0 alors le buffer est censΘ Ωtre de 8kos, et on recoit par bloc de lignes
  1456. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1457. // SI bufl==-1 alors le buffer est censΘ Ωtre de 8kos, et on recoit ligne par ligne
  1458. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1459. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1460. LLint http_xfread1(htsblk* r,int bufl) {
  1461.   int nl=-1;
  1462.  
  1463.   if (bufl>0) {
  1464.     if (!r->is_write) {     // stocker en mΘmoire
  1465.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1466.         if (r->adr==NULL) {
  1467.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1468.           r->size=0;
  1469.         }
  1470.         if (r->adr!=NULL) {
  1471.           // lecture
  1472.           nl = hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1473.           // nouvelle taille
  1474.           if (nl >= 0) r->size+=nl;
  1475.           
  1476.           if ((nl < 0) || (r->size >= r->totalsize))
  1477.             nl=-1;  // break
  1478.           
  1479.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1480.         }
  1481.         
  1482.       } else {                 // inconnu..
  1483.         // rΘserver de la mΘmoire?
  1484.         if (r->adr==NULL) {
  1485. #if HDEBUG
  1486.           printf("..alloc xfread\n");
  1487. #endif
  1488.           r->adr=(char*) malloct(bufl + 1);
  1489.           r->size=0;
  1490.         }
  1491.         else {
  1492. #if HDEBUG
  1493.           printf("..realloc xfread1\n");
  1494. #endif
  1495.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1496.         }
  1497.         
  1498.         if (r->adr!=NULL) {
  1499.           // lecture
  1500.           nl = hts_read(r,r->adr+(int)r->size,bufl);
  1501.           if (nl>0) {
  1502.             // resize
  1503.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1504.             // nouvelle taille
  1505.             r->size+=nl;
  1506.             // octet nul
  1507.             if (r->adr) r->adr[r->size]='\0';
  1508.  
  1509.           } // sinon on a fini
  1510. #if HDEBUG
  1511.           else if (nl < 0)
  1512.             printf("..end read (%d)\n", nl);
  1513. #endif
  1514.         }
  1515. #if HDEBUG
  1516.         else printf("..-> error\n");
  1517. #endif
  1518.       }
  1519.  
  1520.       // pas de adr=erreur
  1521.       if (r->adr==NULL) nl=-1;
  1522.  
  1523.     } else {    // stocker sur disque
  1524.       char* buff;
  1525.       buff=(char*) malloct(bufl);
  1526.       if (buff!=NULL) {
  1527.         // lecture
  1528.         nl = hts_read(r,buff,bufl);
  1529.         // nouvelle taille
  1530.         if (nl > 0) { 
  1531.           r->size+=nl;
  1532.           if ((INTsys)fwrite(buff,1,nl,r->out)!=nl) {
  1533.             r->statuscode=-1;
  1534.             strcpybuff(r->msg,"Write error on disk");
  1535.             nl=-1;
  1536.           }
  1537.         }
  1538.  
  1539.         if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1540.           nl=-1;  // break
  1541.  
  1542.         // libΘrer bloc tempo
  1543.         freet(buff);
  1544.       } else
  1545.         nl=-1;
  1546.       
  1547.       if ((nl < 0) && (r->out!=NULL)) {
  1548.         fflush(r->out); 
  1549.       }
  1550.         
  1551.         
  1552.     } // stockage disque ou mΘmoire
  1553.  
  1554.   } else if (bufl == -2) {  // force reserve
  1555.     if (r->adr==NULL) {
  1556.       r->adr=(char*) malloct(8192);
  1557.       r->size=0;
  1558.       return 0;
  1559.     }
  1560.     return -1;
  1561.   } else {    // rΘception d'un en-tΩte octet par octet
  1562.     int count=256;
  1563.     int tot_nl=0;
  1564.     int lf_detected=0;
  1565.     int at_begining=1;
  1566.     do {
  1567.       nl=-1;
  1568.       count--;
  1569.       if (r->adr==NULL) {
  1570.         r->adr=(char*) malloct(8192);
  1571.         r->size=0;
  1572.       }
  1573.       if (r->adr!=NULL) {
  1574.         if (r->size < 8190) {
  1575.           // lecture
  1576.           nl = hts_read(r,r->adr+r->size,1);
  1577.           if (nl>0) {
  1578.             // exit if:
  1579.             // lf detected AND already detected before
  1580.             // or
  1581.             // lf detected AND first character read
  1582.             if (*(r->adr+r->size) == 10) {
  1583.               if (lf_detected || (at_begining) || (bufl<0))
  1584.                 count=-1;
  1585.               lf_detected=1;
  1586.             }
  1587.             if (*(r->adr+r->size) != 13) {   // sauter caractΦres 13
  1588.               if (
  1589.                 (*(r->adr+r->size) != 10)
  1590.                 &&
  1591.                 (*(r->adr+r->size) != 13)
  1592.                 ) {
  1593.                 // restart for new line
  1594.                 lf_detected=0;
  1595.               }
  1596.               (r->size)++;
  1597.               at_begining=0;
  1598.             }
  1599.             *(r->adr+r->size)='\0';    // terminer par octet nul
  1600.           }
  1601.         }
  1602.       }
  1603.       if (nl >= 0) {
  1604.         tot_nl+=nl;
  1605.         if (!check_readinput(r))
  1606.           count=-1;
  1607.       }
  1608.     } while((nl >= 0) && (count>0));
  1609.     nl = tot_nl;
  1610.   }
  1611. #if HDEBUG
  1612.   //printf("add to %d / %d\n",r->size,r->totalsize);
  1613. #endif
  1614.   // nl == 0 may mean "no relevant data", for example is using cache or ssl
  1615. #if HTS_USEOPENSSL
  1616.   if (r->ssl)
  1617.     return nl;
  1618.   else
  1619. #endif
  1620.     return ((nl > 0) ? nl : -1);        // ==0 is fatal if direct read
  1621. }
  1622.  
  1623.  
  1624. // teste une adresse, et suit l'Θventuel chemin "moved"
  1625. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1626. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1627. htsblk http_location(char* adr,char* fil,char* loc) {
  1628.   htsblk retour;
  1629.   int retry=0;
  1630.   int tryagain;
  1631.   // note: "RFC says"
  1632.   // 5 boucles au plus, on en teste au plus 8 ici
  1633.   // sinon abandon..
  1634.   do {
  1635.     tryagain=0;
  1636.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1637.     case 200: break;   // ok!
  1638.     case 301: case 302: case 303: case 307: // moved!
  1639.       // recalculer adr et fil!
  1640.       if (ident_url_absolute(loc,adr,fil)!=-1) {
  1641.         tryagain=1;  // retenter
  1642.         retry++;     // ..encore une fois
  1643.       }
  1644.     }
  1645.   } while((tryagain) && (retry<5+3));
  1646.   return retour;
  1647. }
  1648.  
  1649.  
  1650. // teste si une URL (validitΘ, header, taille)
  1651. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1652. // en cas de moved xx, dans location
  1653. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1654. // qui nous font poireauter 5 heures..) -> -2=timeout
  1655. htsblk http_test(char* adr,char* fil,char* loc) {
  1656.   T_SOC soc;
  1657.   htsblk retour;
  1658.   //int rcvsize=-1;
  1659.   //char* rcv=NULL;    // adresse de retour
  1660.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1661.   TStamp tl;
  1662.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1663.  
  1664.   // pour abandonner un site trop lent
  1665.   tl=time_local();
  1666.  
  1667.   loc[0]='\0';
  1668.   memset(&retour, 0, sizeof(htsblk));    // effacer
  1669.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1670.  
  1671.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1672.  
  1673.   // on ouvre en head, et on traite l'en tΩte
  1674.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1675.   
  1676.   if (soc!=INVALID_SOCKET) {
  1677.     int e=0;
  1678.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1679.     do {
  1680.       if (http_xfread1(&retour,0) < 0)
  1681.         e=1;
  1682.       else {
  1683.         if (retour.adr!=NULL) {
  1684.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1685.             e=1;
  1686.         }
  1687.       }
  1688.             
  1689.       if (!e) {
  1690.         if ((time_local()-tl)>=timeout) {
  1691.           e=-1;
  1692.         }
  1693.       }
  1694.       
  1695.     } while (!e);
  1696.     
  1697.     if (e==1) {
  1698.       if (adr!=NULL) {
  1699.         int ptr=0;
  1700.         char rcvd[1100];
  1701.  
  1702.         // note: en gros recopie du traitement de back_wait()
  1703.         //
  1704.  
  1705.  
  1706.         // ----------------------------------------
  1707.         // traiter en-tΩte!
  1708.         // status-line α rΘcupΘrer
  1709.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1710.         if (strnotempty(rcvd)==0)
  1711.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1712.         
  1713.         // traiter status-line
  1714.         treatfirstline(&retour,rcvd);
  1715.         
  1716. #if HDEBUG
  1717.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1718. #endif
  1719.         
  1720.         // en-tΩte
  1721.         
  1722.         // header // ** !attention! HTTP/0.9 non supportΘ
  1723.         do {
  1724.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  1725. #if HDEBUG
  1726.           printf("(buffer)>%s\n",rcvd);      
  1727. #endif
  1728.           if (strnotempty(rcvd))
  1729.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  1730.           
  1731.         } while(strnotempty(rcvd));
  1732.         // ----------------------------------------                    
  1733.         
  1734.         // libΘrer mΘmoire
  1735.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  1736.       }
  1737.     } else {
  1738.       retour.statuscode=-2;
  1739.       strcpybuff(retour.msg,"Timeout While Testing");
  1740.     }
  1741.     
  1742.     
  1743. #if HTS_DEBUG_CLOSESOCK
  1744.     DEBUG_W("http_test: deletehttp\n");
  1745. #endif
  1746.     deletehttp(&retour);
  1747.     retour.soc=INVALID_SOCKET;
  1748.   }
  1749.   return retour;    
  1750. }
  1751.  
  1752. // CrΘe un lien (http) vers une adresse internet iadr
  1753. // retour: structure (adresse, taille, message si erreur (si !adr))
  1754. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  1755. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  1756.   t_fullhostent fullhostent_buffer;    // buffer pour resolver
  1757.   T_SOC soc;                           // descipteur de la socket
  1758.   char* iadr;
  1759.   // unsigned short int port;
  1760.   
  1761.   // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  1762.   iadr = jump_identification(_iadr);
  1763.   
  1764.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  1765.   // local.
  1766.   // utile pour les tests!
  1767.   //## if (iadr[0]!=lOCAL_CHAR) {
  1768.   if (strcmp(_iadr,"file://")) {           /* non fichier */
  1769.     SOCaddr server;
  1770.     int server_size=sizeof(server);
  1771.     t_hostent* hp;    
  1772.     // effacer structure
  1773.     memset(&server, 0, sizeof(server));
  1774.  
  1775. #if HDEBUG
  1776.     printf("gethostbyname\n");
  1777. #endif
  1778.     
  1779.     // tester un Θventuel port
  1780.     if (port==-1) {
  1781.       char *a=jump_toport(iadr);
  1782. #if HTS_USEOPENSSL
  1783.       if (retour->ssl)
  1784.         port=443;
  1785.       else
  1786.         port=80;    // port par dΘfaut
  1787. #else
  1788.       port=80;    // port par dΘfaut
  1789. #endif
  1790.       if (a) {
  1791.         char iadr2[HTS_URLMAXSIZE*2];
  1792.         int i=-1;
  1793.         iadr2[0]='\0';
  1794.         sscanf(a+1,"%d",&i);
  1795.         if (i!=-1) {
  1796.           port=(unsigned short int) i;
  1797.         }
  1798.         
  1799.         // adresse vΘritable (sans :xx)
  1800.         strncatbuff(iadr2,iadr,(int) (a - iadr));
  1801.  
  1802.         // adresse sans le :xx
  1803.         hp = hts_gethostbyname(iadr2, &fullhostent_buffer);
  1804.         
  1805.       } else {
  1806.  
  1807.         // adresse normale (port par dΘfaut par la suite)
  1808.         hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  1809.         
  1810.       }
  1811.       
  1812.     } else    // port dΘfini
  1813.       hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  1814.  
  1815.     
  1816.     // Conversion iadr -> adresse
  1817.     // structure recevant le nom de l'h⌠te, etc
  1818.     //struct     hostent     *hp;
  1819.     if (hp == NULL) {
  1820. #if DEBUG
  1821.       printf("erreur gethostbyname\n");
  1822. #endif
  1823.       if (retour)
  1824.       if (retour->msg)
  1825.         strcpybuff(retour->msg,"Unable to get server's address");
  1826.       return INVALID_SOCKET;
  1827.     }  
  1828.     // copie adresse
  1829.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  1830.     // memcpy(&SOCaddr_sinaddr(server), hp->h_addr_list[0], hp->h_length);
  1831.      
  1832.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  1833. #if HDEBUG
  1834.     printf("socket\n");
  1835. #endif
  1836. #if HTS_WIDE_DEBUG    
  1837.     DEBUG_W("socket\n");
  1838. #endif
  1839.     soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  1840.     if (retour != NULL) {
  1841.       retour->debugid = HTS_STAT.stat_sockid++;
  1842.     }
  1843. #if HTS_WIDE_DEBUG    
  1844.     DEBUG_W("socket done\n");
  1845. #endif
  1846.     if (soc==INVALID_SOCKET) {
  1847.       if (retour)
  1848.       if (retour->msg)
  1849.         strcpybuff(retour->msg,"Unable to create a socket");
  1850.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  1851.     }
  1852.     // structure: connexion au domaine internet, port 80 (ou autre)
  1853.     SOCaddr_initport(server, port);
  1854. #if HDEBUG
  1855.     printf("==%d\n",soc);
  1856. #endif
  1857.  
  1858.     // connexion non bloquante?
  1859.     if (!waitconnect ) {
  1860.       unsigned long p=1;  // non bloquant
  1861. #if HTS_WIN
  1862.       ioctlsocket(soc,FIONBIO,&p);
  1863. #else
  1864.       ioctl(soc,FIONBIO,&p);
  1865. #endif
  1866.     }
  1867.     
  1868.     // Connexion au serveur lui mΩme
  1869. #if HDEBUG
  1870.     printf("connect\n");
  1871. #endif
  1872.     
  1873. #if HTS_WIDE_DEBUG
  1874.     DEBUG_W("connect\n");
  1875. #endif
  1876. #if HTS_WIN
  1877.     if (connect(soc, (const struct sockaddr FAR *)&server, server_size) != 0) {
  1878. #else
  1879.       if (connect(soc, (struct sockaddr *)&server, server_size) == -1) {
  1880. #endif
  1881.  
  1882.         // no - non blocking
  1883.         //deletesoc(soc);
  1884.         //soc=INVALID_SOCKET;
  1885.  
  1886.         // bloquant
  1887.         if (waitconnect) {
  1888. #if HDEBUG
  1889.           printf("unable to connect!\n");
  1890. #endif
  1891.           if (retour)
  1892.           if (retour->msg)
  1893.             strcpybuff(retour->msg,"Unable to connect to the server");
  1894.           /* Close the socket and notify the error!!! */
  1895.           deletesoc(soc);
  1896.           return INVALID_SOCKET;
  1897.         }
  1898.       }
  1899. #if HTS_WIDE_DEBUG    
  1900.       DEBUG_W("connect done\n");
  1901. #endif
  1902.       
  1903. #if HDEBUG
  1904.       printf("connexion Θtablie\n");
  1905. #endif
  1906.     
  1907.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  1908.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  1909.     // read(soc,adr,taille)
  1910.  
  1911.   } else {    // on doit ouvrir un fichier local!
  1912.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  1913.  
  1914.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  1915.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  1916.  
  1917.   }   // teste fichier local ou http
  1918.   
  1919.   return soc;
  1920. }
  1921.  
  1922.  
  1923.  
  1924. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  1925. // retour=-1 si erreur.
  1926. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  1927. int ident_url_absolute(char* url,char* adr,char* fil) {
  1928.   int pos=0;
  1929.   int scheme=0;
  1930.  
  1931.   // effacer adr et fil
  1932.   adr[0]=fil[0]='\0';
  1933.   
  1934. #if HDEBUG
  1935.   printf("protocol: %s\n",url);
  1936. #endif
  1937.  
  1938.   // Scheme?
  1939.   {
  1940.     char* a=url;
  1941.     while (isalpha((unsigned char)*a))
  1942.       a++;
  1943.     if (*a == ':')
  1944.       scheme=1;
  1945.   }
  1946.  
  1947.   // 1. optional scheme ":"
  1948.   if ((pos=strfield(url,"file:"))) {    // fichier local!! (pour les tests)
  1949.     //!! p+=3;
  1950.     strcpybuff(adr,"file://");
  1951.   } else if ((pos=strfield(url,"http:"))) {    // HTTP
  1952.     //!!p+=3;
  1953.   } else if ((pos=strfield(url,"ftp:"))) {    // FTP
  1954.     strcpybuff(adr,"ftp://");    // FTP!!
  1955.     //!!p+=3;
  1956. #if HTS_USEOPENSSL
  1957.   } else if (SSL_is_available && (pos=strfield(url,"https:"))) {    // HTTPS
  1958.     strcpybuff(adr,"https://");
  1959. #endif
  1960.   } else if (scheme) {
  1961.     return -1;    // erreur non reconnu
  1962.   } else
  1963.     pos=0;
  1964.  
  1965.   // 2. optional "//" authority
  1966.   if (strncmp(url+pos,"//",2)==0)
  1967.     pos+=2;
  1968.  
  1969.   // (url+pos) now points to the path (not net path)
  1970.  
  1971.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  1972.   if (!strfield(adr,"file:")) {      // PAS file://
  1973.     char *p,*q;
  1974.     p=url+pos;
  1975.  
  1976.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  1977.     q=strchr(jump_identification(p),'/');
  1978.     if (q==0) q=strchr(jump_identification(p),'?');     // http://www.foo.com?bar=1
  1979.     if (q==0) q=p+strlen(p);  // pointe sur \0
  1980.     // q pointe sur le chemin, ex: index.html?query=recherche
  1981.     
  1982.     // chemin www... trop long!!
  1983.     if ( ( ((int) (q - p)) )  > HTS_URLMAXSIZE) {
  1984.       //strcpybuff(retour.msg,"Path too long");
  1985.       return -1;    // erreur
  1986.     }
  1987.     
  1988.     // recopier adresse www..
  1989.     strncatbuff(adr,p, ((int) (q - p)) );
  1990.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  1991.     // recopier chemin /pub/..
  1992.     if (q[0] != '/')    // page par dΘfaut (/)
  1993.       strcatbuff(fil,"/");
  1994.     strcatbuff(fil,q);
  1995.     // SECURITE:
  1996.     // simplifier url pour les ../
  1997.     fil_simplifie(fil);
  1998.   } else {    // localhost file://
  1999.     char *p;
  2000.     int i;
  2001.     char* a;
  2002.  
  2003.     p=url+pos;
  2004.     
  2005.     strcatbuff(fil,p);    // fichier local ; adr="#"
  2006.     a=strchr(fil,'?');
  2007.     if (a) 
  2008.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  2009.     // filtrer les \\ -> / pour les fichiers DOS
  2010.     for(i=0;i<(int) strlen(fil);i++)
  2011.       if (fil[i]=='\\')
  2012.         fil[i]='/';
  2013.   }
  2014.  
  2015.   // no hostname
  2016.   if (!strnotempty(adr))
  2017.     return -1;    // erreur non reconnu
  2018.  
  2019.   // nommer au besoin.. (non utilisΘ normalement)
  2020.   if (!strnotempty(fil))
  2021.     strcpybuff(fil,"default-index.html");
  2022.  
  2023.   // case insensitive pour adresse
  2024.   {
  2025.     char *a=jump_identification(adr);
  2026.     while(*a) {
  2027.       if ((*a>='A') && (*a<='Z'))
  2028.         *a+='a'-'A';       
  2029.       a++;
  2030.     }
  2031.   }
  2032.   
  2033.   return 0;
  2034. }
  2035.  
  2036. // simplification des ../
  2037. void fil_simplifie(char* f) {
  2038.   int i=0;
  2039.   int last=0;
  2040.   char* a;
  2041.  
  2042.   // Θliminer ../
  2043.   while (f[i]) {
  2044.     
  2045.     if (f[i]=='/') {
  2046.       if (f[i+1]=='.')
  2047.       if (f[i+2]=='.')      // couper dernier rΘpertoire
  2048.       if (f[i+3]=='/')      // Θviter les /tmp/..coolandlamedir/
  2049.       {    // couper dernier rΘpertoire
  2050.         char tempo[HTS_URLMAXSIZE*2];
  2051.         tempo[0]='\0';
  2052.         //
  2053.         if (!last)                /* can't go upper.. */
  2054.           strcpybuff(tempo,"/");
  2055.         else
  2056.           strncpy(tempo,f,last+1);
  2057.         tempo[last+1]='\0';
  2058.         strcatbuff(tempo,f+i+4);
  2059.         strcpybuff(f,tempo);    // remplacer
  2060.         i=-1;             // recommencer
  2061.         last=0;
  2062.       }
  2063.       
  2064.       if (i>=0)
  2065.         last=i;
  2066.       else
  2067.         last=0;
  2068.     }
  2069.     
  2070.     i++;
  2071.   }
  2072.  
  2073.   // Θliminer ./
  2074.   while ( (a=strstr(f,"./")) ) {
  2075.     char tempo[HTS_URLMAXSIZE*2];
  2076.     tempo[0]='\0';
  2077.     strcpybuff(tempo,a+2);
  2078.     strcpybuff(a,tempo);
  2079.   }
  2080.   // delete all remaining ../ (potential threat)
  2081.   while ( (a=strstr(f,"../")) ) {
  2082.     char tempo[HTS_URLMAXSIZE*2];
  2083.     tempo[0]='\0';
  2084.     strcpybuff(tempo,a+3);
  2085.     strcpybuff(a,tempo);
  2086.   }
  2087.   
  2088. }
  2089.  
  2090. // fermer liaison fichier ou socket
  2091. HTS_INLINE void deletehttp(htsblk* r) {
  2092. #if HTS_DEBUG_CLOSESOCK
  2093.     char info[256];
  2094.     sprintf(info,"deletehttp: (htsblk*) %d\n",r);
  2095.     DEBUG_W2(info);
  2096. #endif
  2097. #if HTS_USEOPENSSL
  2098.     /* Free OpenSSL structures */
  2099.     if (SSL_is_available && r->ssl_con) {
  2100.       SSL_shutdown(r->ssl_con);
  2101.       SSL_free(r->ssl_con);
  2102.       r->ssl_con=NULL;
  2103.     }
  2104. #endif  
  2105.   if (r->soc!=INVALID_SOCKET) {
  2106.     if (r->is_file) {
  2107.       if (r->fp)
  2108.         fclose(r->fp);
  2109.       r->fp=NULL;
  2110.     } else {
  2111.       if (r->soc!=LOCAL_SOCKET_ID)
  2112.         deletesoc_r(r);
  2113.     }
  2114.     r->soc=INVALID_SOCKET;
  2115.   }
  2116. }
  2117.  
  2118. // fermer une socket
  2119. HTS_INLINE void deletesoc(T_SOC soc) {
  2120.   if (soc!=INVALID_SOCKET) {
  2121. // J'ai plantΘ.. pas de shutdown
  2122. //#if HTS_WIDE_DEBUG    
  2123. //    DEBUG_W("shutdown\n");
  2124. //#endif
  2125. //    shutdown(soc,2);  // shutdown
  2126. //#if HTS_WIDE_DEBUG    
  2127. //    DEBUG_W("shutdown done\n");
  2128. //#endif
  2129.     // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
  2130. #if HTS_WIDE_DEBUG    
  2131.     DEBUG_W("close\n");
  2132. #endif
  2133. #if HTS_WIN
  2134.     closesocket(soc);
  2135. #else
  2136.     close(soc);
  2137. #endif
  2138. #if HTS_WIDE_DEBUG    
  2139.     DEBUG_W("close done\n");
  2140. #endif
  2141.   }
  2142. }
  2143.  
  2144. /* Will also clean other things */
  2145. HTS_INLINE void deletesoc_r(htsblk* r) {
  2146. #if HTS_USEOPENSSL
  2147.   if (SSL_is_available && r->ssl_con) {
  2148.     SSL_shutdown(r->ssl_con);
  2149.     // SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
  2150.     SSL_free(r->ssl_con);
  2151.     r->ssl_con=NULL;
  2152.   }
  2153. #endif
  2154.   deletesoc(r->soc);
  2155.   r->soc=INVALID_SOCKET;
  2156. }
  2157.  
  2158. // renvoi le nombre de secondes depuis 1970
  2159. HTS_INLINE TStamp time_local(void) {
  2160.   return ((TStamp) time(NULL));
  2161. }
  2162.  
  2163. // number of millisec since 1970
  2164. HTSEXT_API HTS_INLINE TStamp mtime_local(void) {
  2165. #ifndef HTS_DO_NOT_USE_FTIME
  2166.   struct timeb B;
  2167.   ftime( &B );
  2168.   return (TStamp) ( ((TStamp) B.time * (TStamp) 1000)
  2169.         + ((TStamp) B.millitm) );
  2170. #else
  2171.   // not precise..
  2172.   return (TStamp) ( ((TStamp) time_local() * (TStamp) 1000)
  2173.         + ((TStamp) 0) );
  2174. #endif
  2175. }
  2176.  
  2177. // convertit un nombre de secondes en temps (chaine)
  2178. void sec2str(char *st,TStamp t) {
  2179.   int j,h,m,s;
  2180.   
  2181.   j=(int) (t/(3600*24));
  2182.   t-=((TStamp) j)*(3600*24);
  2183.   h=(int) (t/(3600));
  2184.   t-=((TStamp) h)*3600;
  2185.   m=(int) (t/60);
  2186.   t-=((TStamp) m)*60;
  2187.   s=(int) t;
  2188.   
  2189.   if (j>0)
  2190.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  2191.   else if (h>0)
  2192.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  2193.   else if (m>0)
  2194.     sprintf(st,"%d minutes %d seconds",m,s);
  2195.   else
  2196.     sprintf(st,"%d seconds",s);
  2197. }
  2198.  
  2199. // idem, plus court (chaine)
  2200. HTSEXT_API void qsec2str(char *st,TStamp t) {
  2201.   int j,h,m,s;
  2202.   
  2203.   j=(int) (t/(3600*24));
  2204.   t-=((TStamp) j)*(3600*24);
  2205.   h=(int) (t/(3600));
  2206.   t-=((TStamp) h)*3600;
  2207.   m=(int) (t/60);
  2208.   t-=((TStamp) m)*60;
  2209.   s=(int) t;
  2210.   
  2211.   if (j>0)
  2212.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  2213.   else if (h>0)
  2214.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  2215.   else if (m>0)
  2216.     sprintf(st,"%dmin%02ds",m,s);
  2217.   else
  2218.     sprintf(st,"%ds",s);
  2219. }
  2220.  
  2221.  
  2222. // heure actuelle, GMT, format rfc (taille buffer 256o)
  2223. void time_gmt_rfc822(char* s) {
  2224.   time_t tt;
  2225.   struct tm* A;
  2226.   tt=time(NULL);
  2227.   A=gmtime(&tt);
  2228.   if (A==NULL)
  2229.     A=localtime(&tt);
  2230.   time_rfc822(s,A);
  2231. }
  2232.  
  2233. // heure actuelle, format rfc (taille buffer 256o)
  2234. void time_local_rfc822(char* s) {
  2235.   time_t tt;
  2236.   struct tm* A;
  2237.   tt=time(NULL);
  2238.   A=localtime(&tt);
  2239.   time_rfc822_local(s,A);
  2240. }
  2241.  
  2242. /* convertir une chaine en temps */
  2243. struct tm* convert_time_rfc822(char* s) {
  2244.   struct tm* result;
  2245.   /* */
  2246.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  2247.   char str[256];
  2248.   char* a;
  2249.   /* */
  2250.   int result_mm=-1;
  2251.   int result_dd=-1;
  2252.   int result_n1=-1;
  2253.   int result_n2=-1;
  2254.   int result_n3=-1;
  2255.   int result_n4=-1;
  2256.   /* */
  2257.   NOSTATIC_RESERVE(result, struct tm, 1);
  2258.  
  2259.   if ((int) strlen(s) > 200)
  2260.     return NULL;
  2261.   strcpybuff(str,s);
  2262.   hts_lowcase(str);
  2263.   /* Θliminer :,- */
  2264.   while( (a=strchr(str,'-')) ) *a=' ';
  2265.   while( (a=strchr(str,':')) ) *a=' ';
  2266.   while( (a=strchr(str,',')) ) *a=' ';
  2267.   /* tokeniser */
  2268.   a=str;
  2269.   while(*a) {
  2270.     char *first,*last;
  2271.     char tok[256];
  2272.     /* dΘcouper mot */
  2273.     while(*a==' ') a++;   /* sauter espaces */
  2274.     first=a;
  2275.     while((*a) && (*a!=' ')) a++;
  2276.     last=a;
  2277.     tok[0]='\0';
  2278.     if (first!=last) {
  2279.       char* pos;
  2280.       strncatbuff(tok,first,(int) (last - first));
  2281.       /* analyser */
  2282.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  2283.         result_mm=((int) (pos - months))/4;
  2284.       } else {
  2285.         int number;
  2286.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  2287.           if (result_dd<0)                        /* day always first number */
  2288.             result_dd=number;
  2289.           else if (result_n1<0)
  2290.             result_n1=number;
  2291.           else if (result_n2<0)
  2292.             result_n2=number;
  2293.           else if (result_n3<0)
  2294.             result_n3=number;
  2295.           else if (result_n4<0)
  2296.             result_n4=number;
  2297.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  2298.       }
  2299.     }
  2300.   }
  2301.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  2302.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  2303.       result->tm_year=result_n4-1900;
  2304.       result->tm_hour=result_n1;
  2305.       result->tm_min=result_n2;
  2306.       result->tm_sec=max(result_n3,0);
  2307.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  2308.       result->tm_hour=result_n2;
  2309.       result->tm_min=result_n3;
  2310.       result->tm_sec=max(result_n4,0);
  2311.       if (result_n1<=50)                /* 00 means 2000 */
  2312.         result->tm_year=result_n1+100;
  2313.       else if (result_n1<1000)          /* 99 means 1999 */
  2314.         result->tm_year=result_n1;
  2315.       else                              /* 2000 */
  2316.         result->tm_year=result_n1-1900;
  2317.     }
  2318.     result->tm_isdst=0;        /* assume GMT */
  2319.     result->tm_yday=-1;        /* don't know */
  2320.     result->tm_wday=-1;        /* don't know */
  2321.     result->tm_mon=result_mm;
  2322.     result->tm_mday=result_dd;
  2323.     return result;
  2324.   }
  2325.   return NULL;
  2326. }
  2327.  
  2328. /* sets file time. -1 if error */
  2329. int set_filetime(char* file,struct tm* tm_time) {
  2330.   struct utimbuf tim;
  2331. #ifndef HTS_DO_NOT_USE_FTIME
  2332.   struct timeb B;
  2333.   B.timezone=0;
  2334.   ftime( &B );
  2335.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  2336. #else
  2337.   // bogus time (GMT/local)..
  2338.   tim.actime=tim.modtime=mktime(tm_time); 
  2339. #endif
  2340.   return utime(file,&tim);
  2341. }
  2342.  
  2343. /* sets file time from RFC822 date+time, -1 if error*/
  2344. int set_filetime_rfc822(char* file,char* date) {
  2345.   struct tm* tm_s=convert_time_rfc822(date);
  2346.   if (tm_s) {
  2347.     return set_filetime(file,tm_s);
  2348.   } else return -1;
  2349. }
  2350.  
  2351.  
  2352. // heure au format rfc (taille buffer 256o)
  2353. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2354.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2355. }
  2356.  
  2357. // heure locale au format rfc (taille buffer 256o)
  2358. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2359.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2360. }
  2361.  
  2362. // conversion en b,Kb,Mb
  2363. HTSEXT_API char* int2bytes(LLint n) {
  2364.   char** a=int2bytes2(n);
  2365.   char* buff;
  2366.   NOSTATIC_RESERVE(buff, char, 256);
  2367.  
  2368.   strcpybuff(buff,a[0]);
  2369.   strcatbuff(buff,a[1]);
  2370.   return concat(buff,"");
  2371. }
  2372.  
  2373. // conversion en b/s,Kb/s,Mb/s
  2374. HTSEXT_API char* int2bytessec(long int n) {
  2375.   char* buff;
  2376.   char** a=int2bytes2(n);
  2377.   NOSTATIC_RESERVE(buff, char, 256);
  2378.  
  2379.   strcpybuff(buff,a[0]);
  2380.   strcatbuff(buff,a[1]);
  2381.   return concat(buff,"/s");
  2382. }
  2383. HTSEXT_API char* int2char(int n) {
  2384.   char* buffer;
  2385.   NOSTATIC_RESERVE(buffer, char, 32);
  2386.   sprintf(buffer,"%d",n);
  2387.   return concat(buffer,"");
  2388. }
  2389.  
  2390. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2391. // limite: 2.10^9.10^6B
  2392.  
  2393. /* See http://physics.nist.gov/cuu/Units/binary.html */
  2394. #define ToLLint(a) ((LLint)(a))
  2395. #define ToLLintKiB (ToLLint(1024))
  2396. #define ToLLintMiB (ToLLintKiB*ToLLintKiB)
  2397. #ifdef HTS_LONGLONG
  2398. #define ToLLintGiB (ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2399. #define ToLLintTiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2400. #define ToLLintPiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2401. #endif
  2402. typedef struct {
  2403.   char buff1[256];
  2404.   char buff2[32];
  2405.   char* buffadr[2];
  2406. } strc_int2bytes2;
  2407. HTSEXT_API char** int2bytes2(LLint n) {
  2408.   strc_int2bytes2* strc;
  2409.   NOSTATIC_RESERVE(strc, strc_int2bytes2, 1);
  2410.  
  2411.   if (n < ToLLintKiB) {
  2412.     sprintf(strc->buff1,"%d",(int)(LLint)n);
  2413.     strcpybuff(strc->buff2,"B");
  2414.   } else if (n < ToLLintMiB) {
  2415.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/ToLLintKiB)),(int)((LLint)((n%ToLLintKiB)*100)/ToLLintKiB));
  2416.     strcpybuff(strc->buff2,"KiB");
  2417.   }
  2418. #ifdef HTS_LONGLONG
  2419.   else if (n < ToLLintGiB) {
  2420.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2421.     strcpybuff(strc->buff2,"MiB");
  2422.   } else if (n < ToLLintTiB) {
  2423.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintGiB))),(int)((LLint)(((n%(ToLLintGiB))*100)/(ToLLintGiB))));
  2424.     strcpybuff(strc->buff2,"GiB");
  2425.   } else if (n < ToLLintPiB) {
  2426.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintTiB))),(int)((LLint)(((n%(ToLLintTiB))*100)/(ToLLintTiB))));
  2427.     strcpybuff(strc->buff2,"TiB");
  2428.   } else {
  2429.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintPiB))),(int)((LLint)(((n%(ToLLintPiB))*100)/(ToLLintPiB))));
  2430.     strcpybuff(strc->buff2,"PiB");
  2431.   }
  2432. #else
  2433.   else {
  2434.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2435.     strcpybuff(strc->buff2,"MiB");
  2436.   }
  2437. #endif
  2438.   strc->buffadr[0]=strc->buff1;
  2439.   strc->buffadr[1]=strc->buff2;
  2440.   return strc->buffadr;
  2441. }
  2442.  
  2443. #if HTS_WIN
  2444. #else
  2445. // ignore sigpipe?
  2446. int sig_ignore_flag( int setflag ) {     // flag ignore
  2447.   static int flag=0;   /* YES, this one is true static */
  2448.   if (setflag>=0)
  2449.     flag=setflag;
  2450.   return flag;
  2451. }
  2452. #endif
  2453.  
  2454. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2455. HTS_INLINE int sendc(htsblk* r, char* s) {
  2456.   int n;
  2457.  
  2458. #if HTS_WIN
  2459. #else
  2460.   sig_ignore_flag(1);
  2461. #endif
  2462. #if HDEBUG
  2463.   write(0,s,strlen(s));
  2464. #endif
  2465.  
  2466. #if HTS_USEOPENSSL
  2467.   if (SSL_is_available && r->ssl) {
  2468.     n = SSL_write(r->ssl_con, s, strlen(s));
  2469.   } else
  2470. #endif
  2471.     n = send(r->soc,s,strlen(s),0);
  2472.  
  2473. #if HTS_WIN
  2474. #else
  2475.   sig_ignore_flag(0);
  2476. #endif
  2477.  
  2478.   return n;
  2479. }
  2480.  
  2481.  
  2482. // Remplace read
  2483. int finput(int fd,char* s,int max) {
  2484.   char c;
  2485.   int j=0;
  2486.   do {
  2487.     //c=fgetc(fp);
  2488.     if (read(fd,&c,1)<=0) {
  2489.       c=0;
  2490.     }
  2491.     if (c!=0) {
  2492.       switch(c) {
  2493.       case 10: c=0; break;
  2494.       case 13: break;  // sauter ces caractΦres
  2495.       default: s[j++]=c; break;
  2496.       }
  2497.     }
  2498.   }  while((c!=0) && (j<max-1));
  2499.   s[j]='\0';
  2500.   return j;
  2501.  
  2502. // Like linput, but in memory (optimized)
  2503. int binput(char* buff,char* s,int max) {
  2504.   char* end;
  2505.   int count;
  2506.  
  2507.   // clear buffer
  2508.   s[0]='\0';
  2509.   // end of buffer?
  2510.   if ( *buff == '\0')
  2511.     return 1;
  2512.   // find ending \n
  2513.   end=strchr(buff,'\n');
  2514.   // ..or end of buffer
  2515.   if (!end)
  2516.     end=buff+strlen(buff);
  2517.   // then count number of bytes, maximum=max
  2518.   count=min(max,end-buff);
  2519.   // and strip annoying ending cr
  2520.   while( (count>0) && (buff[count] == '\r'))
  2521.     count--;
  2522.   // copy
  2523.   if (count > 0) {
  2524.     strncatbuff(s, buff, count);
  2525.   }
  2526.   // and terminate with a null char
  2527.   s[count]='\0';
  2528.   // then return the supplemental jump offset
  2529.   return (end-buff)+1;
  2530.  
  2531. // Lecture d'une ligne (peut Ωtre unicode α priori)
  2532. int linput(FILE* fp,char* s,int max) {
  2533.   int c;
  2534.   int j=0;
  2535.   do {
  2536.     c=fgetc(fp);
  2537.     if (c!=EOF) {
  2538.       switch(c) {
  2539.         case 13: break;  // sauter CR
  2540.         case 10: c=-1; break;
  2541.         case 9: case 12: break;  // sauter ces caractΦres
  2542.         default: s[j++]=(char) c; break;
  2543.       }
  2544.     }
  2545.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2546.   s[j]='\0';
  2547.   return j;
  2548. }
  2549. int linputsoc(T_SOC soc, char* s, int max) {
  2550.   int c;
  2551.   int j=0;
  2552.   do {
  2553.     unsigned char ch;
  2554.     if (recv(soc, &ch, 1, 0) == 1) {
  2555.       c = ch;
  2556.     } else {
  2557.       c = EOF;
  2558.     }
  2559.     if (c!=EOF) {
  2560.       switch(c) {
  2561.         case 13: break;  // sauter CR
  2562.         case 10: c=-1; break;
  2563.         case 9: case 12: break;  // sauter ces caractΦres
  2564.         default: s[j++]=(char) c; break;
  2565.       }
  2566.     }
  2567.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2568.   s[j]='\0';
  2569.   return j;
  2570. }
  2571. int linputsoc_t(T_SOC soc, char* s, int max, int timeout) {
  2572.   if (check_readinput_t(soc, timeout)) {
  2573.     return linputsoc(soc, s, max);
  2574.   }
  2575.   return -1;
  2576. }
  2577. int linput_trim(FILE* fp,char* s,int max) {
  2578.   int rlen=0;
  2579.   char* ls=(char*) malloct(max+2);
  2580.   s[0]='\0';
  2581.   if (ls) {
  2582.     char* a;
  2583.     // lire ligne
  2584.     rlen=linput(fp,ls,max);
  2585.     if (rlen) {
  2586.       // sauter espaces et tabs en fin
  2587.       while( (rlen>0) && ((ls[max(rlen-1,0)]==' ') || (ls[max(rlen-1,0)]=='\t')) )
  2588.         ls[--rlen]='\0';
  2589.       // sauter espaces en dΘbut
  2590.       a=ls;
  2591.       while((rlen>0) && ((*a==' ') || (*a=='\t'))) {
  2592.         a++;
  2593.         rlen--;
  2594.       }
  2595.       if (rlen>0) {
  2596.         memcpy(s,a,rlen);      // can copy \0 chars
  2597.         s[rlen]='\0';
  2598.       }
  2599.     }
  2600.     //
  2601.     freet(ls);
  2602.   }
  2603.   return rlen;
  2604. }
  2605. int linput_cpp(FILE* fp,char* s,int max) {
  2606.   int rlen=0;
  2607.   s[0]='\0';
  2608.   do {
  2609.     int ret;
  2610.     if (rlen>0)
  2611.     if (s[rlen-1]=='\\')
  2612.       s[--rlen]='\0';      // couper \ final
  2613.     // lire ligne
  2614.     ret=linput_trim(fp,s+rlen,max-rlen);
  2615.     if (ret>0)
  2616.       rlen+=ret;
  2617.   } while((s[max(rlen-1,0)]=='\\') && (rlen<max));
  2618.   return rlen;
  2619. }
  2620.  
  2621. // idem avec les car spΘciaux
  2622. void rawlinput(FILE* fp,char* s,int max) {
  2623.   int c;
  2624.   int j=0;
  2625.   do {
  2626.     c=fgetc(fp);
  2627.     if (c!=EOF) {
  2628.       switch(c) {
  2629.         case 13: break;  // sauter CR
  2630.         case 10: c=-1; break;
  2631.         default: s[j++]=(char) c; break;
  2632.       }
  2633.     }
  2634.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2635.   s[j++]='\0';
  2636. }
  2637.  
  2638.  
  2639. // compare le dΘbut de f avec s et retourne la position de la fin
  2640. // 'A=a' (case insensitive)
  2641. int strfield(const char* f,const char* s) {
  2642.   int r=0;
  2643.   while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
  2644.   if (*s==0)
  2645.     return r;
  2646.   else
  2647.     return 0;
  2648. }
  2649.  
  2650. //cherche chaine, case insensitive
  2651. char* strstrcase(char *s,char *o) {
  2652.   while((*s) && (strfield(s,o)==0)) s++;
  2653.   if (*s=='\0') return NULL;
  2654.   return s;  
  2655. }
  2656.  
  2657.  
  2658. // Unicode detector
  2659. // See http://www.unicode.org/unicode/reports/tr28/
  2660. // (sect Table 3.1B. Legal UTF-8 Byte Sequences)
  2661. typedef struct {
  2662.   unsigned int pos;
  2663.   unsigned char data[4];
  2664. } t_auto_seq;
  2665.  
  2666. // char between a and b
  2667. #define CHAR_BETWEEN(c, a, b)       ( (c) >= 0x##a ) && ( (c) <= 0x##b )
  2668. // sequence start
  2669. #define SEQBEG                      ( inseq == 0 )
  2670. // in this block
  2671. #define BLK(n,a, b)                 ( (seq.pos >= n) && ((err = CHAR_BETWEEN(seq.data[n], a, b))) )
  2672. #define ELT(n,a)                    BLK(n,a,a)
  2673. // end
  2674. #define SEQEND                      ((ok = 1))
  2675. // sequence started, character will fail if error
  2676. #define IN_SEQ                      ( (inseq = 1) )
  2677. // decoding error
  2678. #define BAD_SEQ                     ( (ok == 0) && (inseq != 0) && (!err) )
  2679. // no sequence started
  2680. #define NO_SEQ                      ( inseq == 0 )
  2681.  
  2682. // is this block an UTF unicode textfile?
  2683. // 0 : no
  2684. // 1 : yes
  2685. // -1: don't know
  2686. int is_unicode_utf8(unsigned char* buffer, unsigned int size) {
  2687.   t_auto_seq seq;
  2688.   unsigned int i;
  2689.   int is_utf=-1;
  2690.  
  2691.   seq.pos=0;
  2692.   for(i=0 ; i < size ; i++) {
  2693.     unsigned int ok=0;
  2694.     unsigned int inseq=0;
  2695.     unsigned int err=0;
  2696.  
  2697.     seq.data[seq.pos]=buffer[i];
  2698.     /**/ if ( SEQBEG && BLK(0,00,7F) && IN_SEQ && SEQEND                                                 ) { }
  2699.     else if ( SEQBEG && BLK(0,C2,DF) && IN_SEQ && BLK(1,80,BF) && SEQEND                                 ) { }
  2700.     else if ( SEQBEG && ELT(0,E0   ) && IN_SEQ && BLK(1,A0,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2701.     else if ( SEQBEG && BLK(0,E1,EC) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2702.     else if ( SEQBEG && ELT(0,ED   ) && IN_SEQ && BLK(1,80,9F) && BLK(2,80,BF) && SEQEND                 ) { }
  2703.     else if ( SEQBEG && BLK(0,EE,EF) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2704.     else if ( SEQBEG && ELT(0,F0   ) && IN_SEQ && BLK(1,90,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2705.     else if ( SEQBEG && BLK(0,F1,F3) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2706.     else if ( SEQBEG && ELT(0,F4   ) && IN_SEQ && BLK(1,80,8F) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2707.     else if ( NO_SEQ ) {    // bad, unknown
  2708.       return 0;
  2709.     }
  2710.     /* */
  2711.     
  2712.     /* Error */
  2713.     if ( BAD_SEQ ) {
  2714.       return 0;
  2715.     }
  2716.  
  2717.     /* unicode character */
  2718.     if (seq.pos > 0)
  2719.       is_utf=1;
  2720.  
  2721.     /* Next */
  2722.     if (ok)
  2723.       seq.pos=0;
  2724.     else
  2725.       seq.pos++;
  2726.  
  2727.     /* Internal error */
  2728.     if (seq.pos >= 4)
  2729.       return 0;
  2730.  
  2731.   }
  2732.  
  2733.   return is_utf;
  2734. }
  2735.  
  2736. void map_characters(unsigned char* buffer, unsigned int size, unsigned int* map) {
  2737.   unsigned int i;
  2738.   memset(map, 0, sizeof(unsigned int) * 256);
  2739.   for(i = 0 ; i < size ; i++) {
  2740.     map[buffer[i]]++;
  2741.   }
  2742. }
  2743.  
  2744.  
  2745. // le fichier est-il un fichier html?
  2746. //  0 : non
  2747. //  1 : oui
  2748. // -1 : on sait pas
  2749. // -2 : on sait pas, pas d'extension
  2750. int ishtml(char* fil) {
  2751.   char *a;
  2752.  
  2753.   // patch pour les truc.html?Choix=toto
  2754.   if ( (a=strchr(fil,'?')) )  // paramΦtres?
  2755.     a--;  // pointer juste avant le ?
  2756.   else
  2757.     a=fil+strlen(fil)-1;  // pointer sur le dernier caractΦre
  2758.  
  2759.   if (*a=='/') return -1;    // rΘpertoire, on sait pas!!
  2760.   //if (*a=='/') return 1;    // ok rΘpertoire, html
  2761.  
  2762.   while ( (*a!='.') && (*a!='/')  && ( a > fil)) a--;
  2763.   if (*a=='.') {  // a une extension
  2764.     char fil_noquery[HTS_URLMAXSIZE*2];
  2765.     fil_noquery[0]='\0';
  2766.     a++;  // pointer sur extension
  2767.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  2768.     a=strchr(fil_noquery,'?');
  2769.     if (a)
  2770.       *a='\0';
  2771.     return ishtml_ext(fil_noquery);     // retour
  2772.   } else return -2;   // indΘterminΘ, par exemple /truc
  2773. }
  2774.  
  2775. // idem, mais pour uniquement l'extension
  2776. int ishtml_ext(char* a) {
  2777.   int html=0;  
  2778.   //
  2779.   if (strfield2(a,"html"))       html = 1;
  2780.   else if (strfield2(a,"htm"))   html = 1;
  2781.   else if (strfield2(a,"shtml")) html = 1;
  2782.   else if (strfield2(a,"phtml")) html = 1;
  2783.   else if (strfield2(a,"htmlx")) html = 1;
  2784.   else if (strfield2(a,"shtm"))  html = 1;
  2785.   else if (strfield2(a,"phtm"))  html = 1;
  2786.   else if (strfield2(a,"htmx"))  html = 1;
  2787.   //
  2788.   // insuccΦs..
  2789.   else {
  2790.     switch(is_knowntype(a)) {
  2791.     case 1:
  2792.       html = 0;     // connu, non html
  2793.       break;
  2794.     case 2:
  2795.       html = 1;     // connu, html
  2796.       break;
  2797.     default:
  2798.       html = -1;    // inconnu..
  2799.       break;
  2800.     }
  2801.   }
  2802.   return html;  
  2803. }
  2804.  
  2805. // error (404,500..)
  2806. HTS_INLINE int ishttperror(int err) {
  2807.   switch (err/100) {
  2808.     case 4: case 5: return 1;
  2809.       break;
  2810.   }
  2811.   return 0;
  2812. }
  2813.  
  2814.  
  2815. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant 
  2816. // une identification
  2817. HTSEXT_API char* jump_identification(char* source) {
  2818.   char *a,*trytofind;
  2819.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  2820.   // mais sauter ftp:// Θventuel
  2821.   a = jump_protocol(source);
  2822.   trytofind = strrchr_limit(a, '@', strchr(a,'/'));
  2823.   return (trytofind != NULL)?trytofind:a;
  2824. }
  2825.  
  2826. // find port (:80) or NULL if not found
  2827. // can handle IPV6 addresses
  2828. HTSEXT_API char* jump_toport(char* source) {
  2829.   char *a,*trytofind;
  2830.   a = jump_identification(source);
  2831.   trytofind = strrchr_limit(a, ']', strchr(source, '/'));    // find last ] (http://[3ffe:b80:1234::1]:80/foo.html)
  2832.   a = strchr( (trytofind)?trytofind:a, ':');
  2833.   return a;
  2834. }
  2835.  
  2836. // strrchr, but not too far
  2837. char* strrchr_limit(char* s, char c, char* limit) {
  2838.   if (limit == NULL) {
  2839.     char* p = strrchr(s, c);
  2840.     return p?(p+1):NULL;
  2841.   } else {
  2842.     char *a=NULL, *p;
  2843.     for(;;) {
  2844.       p=strchr((a)?a:s, c);
  2845.       if ((p >= limit) || (p == NULL))
  2846.         return a;
  2847.       a=p+1;
  2848.     }
  2849.   }
  2850. }
  2851.  
  2852. // retourner adr sans ftp://
  2853. HTS_INLINE char* jump_protocol(char* source) {
  2854.   int p;
  2855.   // scheme
  2856.   // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
  2857.   if ((p=strfield(source,"http:")))
  2858.     source+=p;
  2859.   else if ((p=strfield(source,"ftp:")))
  2860.     source+=p;
  2861.   else if ((p=strfield(source,"https:")))
  2862.     source+=p;
  2863.   else if ((p=strfield(source,"file:")))
  2864.     source+=p;
  2865.   // net_path
  2866.   if (strncmp(source,"//",2)==0)
  2867.     source+=2;
  2868.   return source;
  2869. }
  2870.  
  2871. // codage base 64 a vers b
  2872. void code64(char* a,char* b) {
  2873.   int i1=0,i2=0,i3=0,i4=0;
  2874.   unsigned long store;
  2875.   int n;
  2876.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2877.   b[0]='\0';
  2878.   while(*a) {  
  2879.     // 24 bits
  2880.     n=1; store=0; store |= ((*a++) & 0xff);
  2881.     if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); }
  2882.     if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); }
  2883.     if (n==3) {
  2884.       i4=store & 63;
  2885.       i3=(store>>6) & 63;
  2886.       i2=(store>>12) & 63;
  2887.       i1=(store>>18) & 63;
  2888.     } else if (n==2) {
  2889.       store<<=2;    
  2890.       i3=store & 63;
  2891.       i2=(store>>6) & 63;
  2892.       i1=(store>>12) & 63;
  2893.     } else {
  2894.       store<<=4;
  2895.       i2=store & 63;
  2896.       i1=(store>>6) & 63;
  2897.     }
  2898.     
  2899.     *b++ = _hts_base64[i1];
  2900.     *b++ = _hts_base64[i2];
  2901.     if (n>=2)
  2902.       *b++ = _hts_base64[i3];
  2903.     else
  2904.       *b++ = '=';
  2905.     if (n>=3)
  2906.       *b++ = _hts_base64[i4];
  2907.     else
  2908.       *b++ = '=';
  2909.   }
  2910.   *b++='\0';
  2911. }
  2912.  
  2913. // remplacer " par " etc..
  2914. // buffer MAX 1Ko
  2915. #define strcmpbeg(a, b) strncmp(a, b, strlen(b))
  2916. HTSEXT_API void unescape_amp(char* s) {
  2917.   while(*s) {
  2918.     if (*s=='&') {
  2919.       char* end=strchr(s,';');
  2920.       if ( end && (((int) (end - s)) <= 8) ) {
  2921.         unsigned char c=0;
  2922.         
  2923.         // http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html
  2924.         if (strcmpbeg(s, "&#") == 0) {
  2925.           int num=0;
  2926.           if ( (s[2] == 'x') || (s[2] == 'X')) {
  2927.             if (sscanf(s+3, "%x", &num) == 1) {
  2928.               c=(unsigned char)num;
  2929.             }
  2930.           } else {
  2931.             if (sscanf(s+2, "%d", &num) == 1) {
  2932.               c=(unsigned char)num;
  2933.             }
  2934.           }
  2935.         } else if (strcmpbeg(s, " ")==0)
  2936.           c=32; // hack - c=160;
  2937.         else if (strcmpbeg(s, "¡")==0)
  2938.           c=161;
  2939.         else if (strcmpbeg(s, "¢")==0)
  2940.           c=162;
  2941.         else if (strcmpbeg(s, "£")==0)
  2942.           c=163;
  2943.         else if (strcmpbeg(s, "¤")==0)
  2944.           c=164;
  2945.         else if (strcmpbeg(s, "¥")==0)
  2946.           c=165;
  2947.         else if (strcmpbeg(s, "¦")==0)
  2948.           c=166;
  2949.         else if (strcmpbeg(s, "§")==0)
  2950.           c=167;
  2951.         else if (strcmpbeg(s, "¨")==0)
  2952.           c=168;
  2953.         else if (strcmpbeg(s, "©")==0)
  2954.           c=169;
  2955.         else if (strcmpbeg(s, "ª")==0)
  2956.           c=170;
  2957.         //else if (strcmpbeg(s, "«")==0)
  2958.         //  c=171;
  2959.         else if (strcmpbeg(s, "¬")==0)
  2960.           c=172;
  2961.         //else if (strcmpbeg(s, "­")==0)
  2962.         //  c=173;
  2963.         else if (strcmpbeg(s, "®")==0)
  2964.           c=174;
  2965.         else if (strcmpbeg(s, "¯")==0)
  2966.           c=175;
  2967.         else if (strcmpbeg(s, "°")==0)
  2968.           c=176;
  2969.         else if (strcmpbeg(s, "±")==0)
  2970.           c=177;
  2971.         else if (strcmpbeg(s, "²")==0)
  2972.           c=178;
  2973.         else if (strcmpbeg(s, "³")==0)
  2974.           c=179;
  2975.         else if (strcmpbeg(s, "´")==0)
  2976.           c=180;
  2977.         else if (strcmpbeg(s, "µ")==0)
  2978.           c=181;
  2979.         else if (strcmpbeg(s, "¶")==0)
  2980.           c=182;
  2981.         else if (strcmpbeg(s, "·")==0)
  2982.           c=183;
  2983.         else if (strcmpbeg(s, "¸")==0)
  2984.           c=184;
  2985.         else if (strcmpbeg(s, "¹")==0)
  2986.           c=185;
  2987.         else if (strcmpbeg(s, "º")==0)
  2988.           c=186;
  2989.         //else if (strcmpbeg(s, "»")==0)
  2990.         //  c=187;
  2991.         else if (strcmpbeg(s, "¼")==0)
  2992.           c=188;
  2993.         else if (strcmpbeg(s, "½")==0)
  2994.           c=189;
  2995.         else if (strcmpbeg(s, "¾")==0)
  2996.           c=190;
  2997.         else if (strcmpbeg(s, "¿")==0)
  2998.           c=191;
  2999.         else if (strcmpbeg(s, "À")==0)
  3000.           c=192;
  3001.         else if (strcmpbeg(s, "Á")==0)
  3002.           c=193;
  3003.         else if (strcmpbeg(s, "Â")==0)
  3004.           c=194;
  3005.         else if (strcmpbeg(s, "Ã")==0)
  3006.           c=195;
  3007.         else if (strcmpbeg(s, "Ä")==0)
  3008.           c=196;
  3009.         else if (strcmpbeg(s, "Å")==0)
  3010.           c=197;
  3011.         else if (strcmpbeg(s, "Æ")==0)
  3012.           c=198;
  3013.         else if (strcmpbeg(s, "Ç")==0)
  3014.           c=199;
  3015.         else if (strcmpbeg(s, "È")==0)
  3016.           c=200;
  3017.         else if (strcmpbeg(s, "É")==0)
  3018.           c=201;
  3019.         else if (strcmpbeg(s, "Ê")==0)
  3020.           c=202;
  3021.         else if (strcmpbeg(s, "Ë")==0)
  3022.           c=203;
  3023.         else if (strcmpbeg(s, "Ì")==0)
  3024.           c=204;
  3025.         else if (strcmpbeg(s, "Í")==0)
  3026.           c=205;
  3027.         else if (strcmpbeg(s, "Î")==0)
  3028.           c=206;
  3029.         else if (strcmpbeg(s, "Ï")==0)
  3030.           c=207;
  3031.         else if (strcmpbeg(s, "Ð")==0)
  3032.           c=208;
  3033.         else if (strcmpbeg(s, "Ñ")==0)
  3034.           c=209;
  3035.         else if (strcmpbeg(s, "Ò")==0)
  3036.           c=210;
  3037.         else if (strcmpbeg(s, "Ó")==0)
  3038.           c=211;
  3039.         else if (strcmpbeg(s, "Ô")==0)
  3040.           c=212;
  3041.         else if (strcmpbeg(s, "Õ")==0)
  3042.           c=213;
  3043.         else if (strcmpbeg(s, "Ö")==0)
  3044.           c=214;
  3045.         else if (strcmpbeg(s, "×")==0)
  3046.           c=215;
  3047.         else if (strcmpbeg(s, "Ø")==0)
  3048.           c=216;
  3049.         else if (strcmpbeg(s, "Ù")==0)
  3050.           c=217;
  3051.         else if (strcmpbeg(s, "Ú")==0)
  3052.           c=218;
  3053.         else if (strcmpbeg(s, "Û")==0)
  3054.           c=219;
  3055.         else if (strcmpbeg(s, "Ü")==0)
  3056.           c=220;
  3057.         else if (strcmpbeg(s, "Ý")==0)
  3058.           c=221;
  3059.         else if (strcmpbeg(s, "Þ")==0)
  3060.           c=222;
  3061.         else if (strcmpbeg(s, "ß")==0)
  3062.           c=223;
  3063.         else if (strcmpbeg(s, "à")==0)
  3064.           c=224;
  3065.         else if (strcmpbeg(s, "á")==0)
  3066.           c=225;
  3067.         else if (strcmpbeg(s, "â")==0)
  3068.           c=226;
  3069.         else if (strcmpbeg(s, "ã")==0)
  3070.           c=227;
  3071.         else if (strcmpbeg(s, "ä")==0)
  3072.           c=228;
  3073.         else if (strcmpbeg(s, "å")==0)
  3074.           c=229;
  3075.         else if (strcmpbeg(s, "æ")==0)
  3076.           c=230;
  3077.         else if (strcmpbeg(s, "ç")==0)
  3078.           c=231;
  3079.         else if (strcmpbeg(s, "è")==0)
  3080.           c=232;
  3081.         else if (strcmpbeg(s, "é")==0)
  3082.           c=233;
  3083.         else if (strcmpbeg(s, "ê")==0)
  3084.           c=234;
  3085.         else if (strcmpbeg(s, "ë")==0)
  3086.           c=235;
  3087.         else if (strcmpbeg(s, "ì")==0)
  3088.           c=236;
  3089.         else if (strcmpbeg(s, "í")==0)
  3090.           c=237;
  3091.         else if (strcmpbeg(s, "î")==0)
  3092.           c=238;
  3093.         else if (strcmpbeg(s, "ï")==0)
  3094.           c=239;
  3095.         else if (strcmpbeg(s, "ð")==0)
  3096.           c=240;
  3097.         else if (strcmpbeg(s, "ñ")==0)
  3098.           c=241;
  3099.         else if (strcmpbeg(s, "ò")==0)
  3100.           c=242;
  3101.         else if (strcmpbeg(s, "ó")==0)
  3102.           c=243;
  3103.         else if (strcmpbeg(s, "ô")==0)
  3104.           c=244;
  3105.         else if (strcmpbeg(s, "õ")==0)
  3106.           c=245;
  3107.         else if (strcmpbeg(s, "ö")==0)
  3108.           c=246;
  3109.         else if (strcmpbeg(s, "÷")==0)
  3110.           c=247;
  3111.         else if (strcmpbeg(s, "ø")==0)
  3112.           c=248;
  3113.         else if (strcmpbeg(s, "ù")==0)
  3114.           c=249;
  3115.         else if (strcmpbeg(s, "ú")==0)
  3116.           c=250;
  3117.         else if (strcmpbeg(s, "û")==0)
  3118.           c=251;
  3119.         else if (strcmpbeg(s, "ü")==0)
  3120.           c=252;
  3121.         else if (strcmpbeg(s, "ý")==0)
  3122.           c=253;
  3123.         else if (strcmpbeg(s, "þ")==0)
  3124.           c=254;
  3125.         else if (strcmpbeg(s, "ÿ")==0)
  3126.           c=255;
  3127.         //        
  3128.         else if (strcmpbeg(s,"&")==0)
  3129.           c='&';
  3130.         else if (strcmpbeg(s,">")==0)
  3131.           c='>';
  3132.         else if (strcmpbeg(s,"«")==0)
  3133.           c='\"';
  3134.         else if (strcmpbeg(s,"<")==0)
  3135.           c='<';
  3136.         else if (strcmpbeg(s," ")==0)
  3137.           c=' ';
  3138.         else if (strcmpbeg(s,""")==0)
  3139.           c='\"';
  3140.         else if (strcmpbeg(s,"»")==0)
  3141.           c='\"';
  3142.         else if (strcmpbeg(s,"­")==0)
  3143.           c='-';
  3144.         else if (strcmpbeg(s,"˜")==0)
  3145.           c='~';
  3146.         // remplacer?
  3147.         if (c) {
  3148.           char buff[HTS_URLMAXSIZE*2];
  3149.           buff[0]=(char) c;
  3150.           strcpybuff(buff+1,end+1);
  3151.           strcpybuff(s,buff);
  3152.         }
  3153.       }
  3154.     }
  3155.     s++;
  3156.   }
  3157. }
  3158.  
  3159. // remplacer %20 par ' ', | par : etc..
  3160. // buffer MAX 1Ko
  3161. HTSEXT_API char* unescape_http(char* s) {
  3162.   char* tempo;
  3163.   int i,j=0;
  3164.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  3165.   for (i=0;i<(int) strlen(s);i++) {
  3166.     if (s[i]=='%') {
  3167.       i++;
  3168.       tempo[j++]=(char) ehex(s+i);
  3169.       i++;    // sauter 2 caractΦres finalement
  3170.     }
  3171.     /*
  3172.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3173.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3174.       tempo[j++]=':';
  3175.     }
  3176.     */
  3177.     else
  3178.       tempo[j++]=s[i];
  3179.   }
  3180.   tempo[j++]='\0';
  3181.   return tempo;
  3182. }
  3183.  
  3184. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  3185. HTSEXT_API char* unescape_http_unharm(char* s, int no_high) {
  3186.   char* tempo;
  3187.   int i,j=0;
  3188.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  3189.   for (i=0;i<(int) strlen(s);i++) {
  3190.     if (s[i]=='%') {
  3191.       int nchar=(char) ehex(s+i+1);
  3192.  
  3193.       int test = (  CHAR_RESERVED(nchar)
  3194.                 || CHAR_DELIM(nchar)
  3195.                 || CHAR_UNWISE(nchar)
  3196.                 || CHAR_LOW(nchar)        /* CHAR_SPECIAL */
  3197.                 || CHAR_XXAVOID(nchar) 
  3198.                 || (
  3199.                   (no_high)
  3200.                   &&
  3201.                   CHAR_HIG(nchar)
  3202.                 )
  3203.                 );
  3204.  
  3205.       if (!test) {
  3206.         tempo[j++]=(char) ehex(s+i+1);
  3207.         i+=2;
  3208.       } else {
  3209.         tempo[j++]='%';
  3210.       }
  3211.     }
  3212.     /*
  3213.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3214.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3215.       tempo[j++]=':';
  3216.     }
  3217.     */
  3218.     else
  3219.       tempo[j++]=s[i];
  3220.   }
  3221.   tempo[j++]='\0';
  3222.   return tempo;
  3223. }
  3224.  
  3225. // remplacer " par %xx etc..
  3226. // buffer MAX 1Ko
  3227. HTSEXT_API void escape_spc_url(char* s) {
  3228.   x_escape_http(s,2);
  3229. }
  3230. // smith / john -> smith%20%2f%20john
  3231. HTSEXT_API void escape_in_url(char* s) {
  3232.   x_escape_http(s,1);
  3233. }
  3234. // smith / john -> smith%20/%20john
  3235. HTSEXT_API void escape_uri(char* s) {
  3236.   x_escape_http(s,3);
  3237. }
  3238. HTSEXT_API void escape_uri_utf(char* s) {
  3239.   x_escape_http(s,30);
  3240. }
  3241. HTSEXT_API void escape_check_url(char* s) {
  3242.   x_escape_http(s,0);
  3243. }
  3244. // same as escape_check_url, but returns char*
  3245. HTSEXT_API char* escape_check_url_addr(char* s) {
  3246.   char* adr;
  3247.   escape_check_url(adr = concat(s,""));
  3248.   return adr;
  3249. }
  3250.  
  3251. // strip all control characters
  3252. HTSEXT_API void escape_remove_control(char* s) {
  3253.   unsigned char* ss = (unsigned char*) s;
  3254.   while(*ss) {
  3255.     if (*ss < 32) {    /* CONTROL characters go away! */
  3256.       char tmp[HTS_URLMAXSIZE*2];
  3257.       strcpybuff(tmp, ss+1);
  3258.       strcpybuff(ss, tmp);
  3259.     } else {
  3260.       ss++;
  3261.     }
  3262.   }
  3263. }
  3264.  
  3265.  
  3266. HTSEXT_API void x_escape_http(char* s,int mode) {
  3267.   while(*s) {
  3268.     int test=0;
  3269.     if (mode == 0)
  3270.       test=(strchr("\" ",*s)!=0);
  3271.     else if (mode==1) {
  3272.       test = (  CHAR_RESERVED(*s)
  3273.              || CHAR_DELIM(*s)
  3274.              || CHAR_UNWISE(*s)
  3275.              || CHAR_SPECIAL(*s)
  3276.              || CHAR_XXAVOID(*s) );
  3277.     }
  3278.     else if (mode==2)
  3279.       test=(strchr(" ",*s)!=0);           // n'escaper que espace
  3280.     else if (mode==3) {                   // Θchapper que ce qui est nΘcessaire
  3281.       test = (
  3282.                 CHAR_SPECIAL(*s)
  3283.              || CHAR_XXAVOID(*s) );
  3284.     }
  3285.     else if (mode==30) {                   // Θchapper que ce qui est nΘcessaire
  3286.       test = (
  3287.                 CHAR_LOW(*s)
  3288.              || CHAR_XXAVOID(*s) );
  3289.     }
  3290.  
  3291.     if (test) {
  3292.       char buffer[HTS_URLMAXSIZE*2];
  3293.       int n;
  3294.       n=(int)(unsigned char) *s;
  3295.       strcpybuff(buffer,s+1);
  3296.       sprintf(s,"%%%02x",n);
  3297.       strcatbuff(s,buffer);
  3298.     }
  3299.     s++;
  3300.   }
  3301. }
  3302.  
  3303.  
  3304. HTS_INLINE int ehexh(char c) {
  3305.   if ((c>='0') && (c<='9')) return c-'0';
  3306.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  3307.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  3308.   return 0;
  3309. }
  3310.  
  3311. HTS_INLINE int ehex(char* s) {
  3312.   return 16*ehexh(*s)+ehexh(*(s+1));
  3313.  
  3314. }
  3315.  
  3316. // concat, concatΦne deux chaines et renvoi le rΘsultat
  3317. // permet d'allΘger grandement le code
  3318. // il faut savoir qu'on ne peut mettre plus de 16 concat() dans une expression
  3319. typedef struct {
  3320.   char buff[16][HTS_URLMAXSIZE*2*2];
  3321.   int rol;
  3322. } concat_strc;
  3323. char* concat(const char* a,const char* b) {
  3324.   concat_strc* strc;
  3325.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3326.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3327.   strcpybuff(strc->buff[strc->rol],a);
  3328.   if (b) strcatbuff(strc->buff[strc->rol],b);
  3329.   return strc->buff[strc->rol];
  3330. }
  3331. // conversion fichier / -> antislash
  3332. #if HTS_DOSNAME
  3333. char* __fconv(char* a) {
  3334.   int i;
  3335.   for(i=0;i<(int) strlen(a);i++)
  3336.     if (a[i]=='/')  // convertir
  3337.       a[i]='\\';
  3338.   return a;
  3339. }
  3340. char* fconcat(char* a,char* b) {
  3341.   return __fconv(concat(a,b));
  3342. }
  3343. char* fconv(char* a) {
  3344.   return __fconv(concat(a,""));
  3345. }
  3346. #endif
  3347.  
  3348. /* / et \\ en / */
  3349. char* __fslash(char* a) {
  3350.   int i;
  3351.   for(i=0;i<(int) strlen(a);i++)
  3352.     if (a[i]=='\\')  // convertir
  3353.       a[i]='/';
  3354.   return a;
  3355. }
  3356. char* fslash(char* a) {
  3357.   return __fslash(concat(a,""));
  3358. }
  3359.  
  3360. // conversion minuscules, avec buffer
  3361. char* convtolower(char* a) {
  3362.   concat_strc* strc;
  3363.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3364.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3365.   strcpybuff(strc->buff[strc->rol],a);
  3366.   hts_lowcase(strc->buff[strc->rol]);  // lower case
  3367.   return strc->buff[strc->rol];
  3368. }
  3369.  
  3370. // conversion en minuscules
  3371. void hts_lowcase(char* s) {
  3372.   int i;
  3373.   for(i=0;i<(int) strlen(s);i++)
  3374.     if ((s[i]>='A') && (s[i]<='Z'))
  3375.       s[i]+=('a'-'A');
  3376. }
  3377.  
  3378. // remplacer un caractΦre d'une chaεne dans une autre
  3379. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  3380.   char* a;
  3381.   while ((a=strchr(s,from))!=NULL) {
  3382.     *a=to;
  3383.   }
  3384. }
  3385.  
  3386.  
  3387. // caractΦre espace, guillemets, CR, LF etc..
  3388. /* SECTION OPTIMISEE:
  3389.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  3390.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09\x0c",c)!=NULL)
  3391. */
  3392. /*
  3393. HTS_INLINE int is_space(char c) {
  3394.   if (c==' ')  return 1;  // spc
  3395.   if (c=='"')  return 1;  // quote
  3396.   if (c==10)   return 1;  // lf
  3397.   if (c==13)   return 1;  // cr
  3398.   if (c=='\'') return 1;  // quote
  3399.   //if (c=='`')  return 1;  // backquote      << non
  3400.   if (c==9)    return 1;  // tab
  3401.   return 0;
  3402. }
  3403. */
  3404.  
  3405. // caractΦre espace, CR, LF, TAB
  3406. /*
  3407. HTS_INLINE int is_realspace(char c) {
  3408.   if (c==' ')  return 1;  // spc
  3409.   if (c==10)   return 1;  // lf
  3410.   if (c==13)   return 1;  // cr
  3411.   if (c==9)    return 1;  // tab
  3412.   return 0;
  3413. }
  3414. */
  3415.  
  3416.  
  3417.  
  3418.  
  3419.  
  3420. // deviner type d'un fichier local..
  3421. // ex: fil="toto.gif" -> s="image/gif"
  3422. void guess_httptype(char *s,char *fil) {
  3423.   get_httptype(s,fil,1);
  3424. }
  3425. // idem
  3426. // flag: 1 si toujours renvoyer un type
  3427. void get_httptype(char *s,char *fil,int flag) {
  3428.   if (ishtml(fil)==1)
  3429.     strcpybuff(s,"text/html");
  3430.   else {
  3431.     char *a=fil+strlen(fil)-1;    
  3432.     while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  3433.     if (*a=='.') {
  3434.       int ok=0;
  3435.       int j=0;
  3436.       a++;
  3437.       while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  3438.         if (strfield2(hts_mime[j][1],a)) {
  3439.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  3440.             strcpybuff(s,hts_mime[j][0]);
  3441.             ok=1;
  3442.           }
  3443.         }
  3444.         j++;
  3445.       }
  3446.       
  3447.       if (!ok) if (flag) sprintf(s,"application/%s",a);
  3448.     } else {
  3449.       if (flag) strcpybuff(s,"application/octet-stream");
  3450.     }
  3451.   }
  3452. }
  3453.  
  3454. // get type of fil (php)
  3455. // s: buffer (text/html) or NULL
  3456. // return: 1 if known by user
  3457. int get_userhttptype(int setdefs,char *s,char *ext) {
  3458.   char** buffer=NULL;
  3459.   NOSTATIC_RESERVE(buffer, char*, 1);
  3460.   if (setdefs) {
  3461.     *buffer=s;
  3462.     return 1;
  3463.   } else {
  3464.     if (s)
  3465.       s[0]='\0';
  3466.     if (!ext)
  3467.       return 0;
  3468.     if (*buffer) {
  3469.       char search[1024];
  3470.       char* detect;
  3471.       sprintf(search,"\n%s=",ext);    // php=text/html
  3472.       detect=strstr(*buffer,search);
  3473.       if (!detect) {
  3474.         sprintf(search,"\n%s\n",ext); // php\ncgi=text/html
  3475.         detect=strstr(*buffer,search);
  3476.       }
  3477.       if (detect) {
  3478.         detect=strchr(detect,'=');
  3479.         if (detect) {
  3480.           detect++;
  3481.           if (s) {
  3482.             char* a;
  3483.             a=strchr(detect,'\n');
  3484.             if (a) {
  3485.               strncatbuff(s,detect,(int) (a - detect));
  3486.             }
  3487.           }
  3488.           return 1;
  3489.         }
  3490.       }
  3491.     }
  3492.   }
  3493.   return 0;
  3494. }
  3495. // renvoyer extesion d'un type mime..
  3496. // ex: "image/gif" -> gif
  3497. void give_mimext(char *s,char *st) {   
  3498.   int ok=0;
  3499.   int j=0;
  3500.   s[0]='\0';
  3501.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  3502.     if (strfield2(hts_mime[j][0],st)) {
  3503.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  3504.         strcpybuff(s,hts_mime[j][1]);
  3505.         ok=1;
  3506.       }
  3507.     }
  3508.     j++;
  3509.   }
  3510.   // wrap "x" mimetypes, such as:
  3511.   // application/x-mp3
  3512.   // or
  3513.   // application/mp3
  3514.   if (!ok) {
  3515.     int p;
  3516.     char* a=NULL;
  3517.     if ((p=strfield(st,"application/x-")))
  3518.       a=st+p;
  3519.     else if ((p=strfield(st,"application/")))
  3520.       a=st+p;
  3521.     if (a) {
  3522.       if ((int)strlen(a) >= 1) {
  3523.         if ((int)strlen(a) <= 4) {
  3524.           strcpybuff(s,a);
  3525.           ok=1;
  3526.         }
  3527.       }
  3528.     }
  3529.   }
  3530. }
  3531. // extension connue?..
  3532. //  0 : non
  3533. //  1 : oui
  3534. //  2 : html
  3535. int is_knowntype(char *fil) {
  3536.   int j=0;
  3537.   if (!fil)
  3538.     return 0;
  3539.   while(strnotempty(hts_mime[j][1])) {
  3540.     if (strfield2(hts_mime[j][1],fil)) {
  3541.       if (strfield2(hts_mime[j][0],"text/html"))
  3542.         return 2;
  3543.       else
  3544.         return 1;
  3545.     }
  3546.     j++;
  3547.   }
  3548.  
  3549.   // Known by user?
  3550.   return (is_userknowntype(fil));
  3551. }
  3552. // extension : html,gif..
  3553. char* get_ext(char *fil) {
  3554.   char* fil_noquery;
  3555.   char *a=fil+strlen(fil)-1;    
  3556.   NOSTATIC_RESERVE(fil_noquery, char, HTS_URLMAXSIZE*2);
  3557.  
  3558.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  3559.   if (*a=='.') {
  3560.     fil_noquery[0]='\0';
  3561.     a++;  // pointer sur extension
  3562.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  3563.     a=strchr(fil_noquery,'?');
  3564.     if (a)
  3565.       *a='\0';
  3566.     return concat(fil_noquery,"");
  3567.   }
  3568.   else
  3569.     return "";
  3570. }
  3571. // known type?..
  3572. //  0 : no
  3573. //  1 : yes
  3574. //  2 : html
  3575. // setdefs : set mime buffer:
  3576. //   file=(char*) "asp=text/html\nphp=text/html\n"
  3577. int is_userknowntype(char *fil) {
  3578.   char mime[1024];
  3579.   if (!fil)
  3580.     return 0;
  3581.   if (!strnotempty(fil))
  3582.     return 0;
  3583.   mime[0]='\0';
  3584.   get_userhttptype(0,mime,fil);
  3585.   if (!strnotempty(mime))
  3586.     return 0;
  3587.   else if (strfield2(mime,"text/html"))
  3588.     return 2;
  3589.   else
  3590.     return 1;
  3591. }
  3592.  
  3593. // page dynamique?
  3594. // is_dyntype(get_ext("foo.asp"))
  3595. int is_dyntype(char *fil) {
  3596.   int j=0;
  3597.   if (!fil)
  3598.     return 0;
  3599.   if (!strnotempty(fil))
  3600.     return 0;
  3601.   while(strnotempty(hts_ext_dynamic[j])) {
  3602.     if (strfield2(hts_ext_dynamic[j],fil)) {
  3603.       return 1;
  3604.     }
  3605.     j++;
  3606.   }
  3607.   return 0;
  3608. }
  3609.  
  3610. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  3611. // connaissent pas le type
  3612. int may_unknown(char* st) {
  3613.   int j=0;
  3614.   // types mΘdia
  3615.   if (may_be_hypertext_mime(st))
  3616.     return 1;
  3617.   while(strnotempty(hts_mime_keep[j])) {
  3618.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  3619.       return 1;
  3620.     }
  3621.     j++;
  3622.   }    
  3623.   return 0;
  3624. }
  3625.  
  3626.  
  3627.  
  3628. // -- Utils fichiers
  3629.  
  3630. // pretty print for i/o
  3631. void fprintfio(FILE* fp,char* buff,char* prefix) {
  3632.   char nl=1;
  3633.   while(*buff) {
  3634.     switch(*buff) {
  3635.     case 13: break;
  3636.     case 10:
  3637.       fprintf(fp,"\r\n");
  3638.       nl=1;
  3639.     break;
  3640.     default:
  3641.       if (nl)
  3642.         fprintf(fp,prefix);
  3643.       nl=0;
  3644.       fputc(*buff,fp);
  3645.     }
  3646.     buff++;
  3647.   }
  3648. }
  3649.  
  3650. /* Le fichier existe-t-il? (ou est-il accessible?) */
  3651. int fexist(char* s) {
  3652.   struct stat st;
  3653.   memset(&st, 0, sizeof(st));
  3654.   if (stat(s, &st) == 0) {
  3655.     if (S_ISREG(st.st_mode)) {
  3656.       return 1;
  3657.     }
  3658.   }
  3659.   return 0;
  3660.  
  3661. /* Taille d'un fichier, -1 si n'existe pas */
  3662. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  3663. /* Note: NOT YET READY FOR 64-bit */
  3664. INTsys fsize(char* s) {
  3665.   FILE* fp;
  3666.   if (strnotempty(s)==0)     // nom vide: erreur
  3667.     return -1;
  3668.   fp=fopen(fconv(s),"rb");
  3669.   if (fp!=NULL) {
  3670.     INTsys i;
  3671.     fseek(fp,0,SEEK_END);
  3672. #ifdef HTS_FSEEKO
  3673.     i=ftello(fp);
  3674. #else
  3675.     i=ftell(fp);
  3676. #endif
  3677.     fclose(fp);
  3678.     return i;
  3679.   } else return -1;
  3680. }
  3681.  
  3682. INTsys fpsize(FILE* fp) {
  3683.   INTsys oldpos,size;
  3684.   if (!fp)
  3685.     return -1;
  3686. #ifdef HTS_FSEEKO
  3687.   oldpos=ftello(fp);
  3688. #else
  3689.   oldpos=ftell(fp);
  3690. #endif
  3691.   fseek(fp,0,SEEK_END);
  3692. #ifdef HTS_FSEEKO
  3693.   size=ftello(fp);
  3694.   fseeko(fp,oldpos,SEEK_SET);
  3695. #else
  3696.   size=ftell(fp);
  3697.   fseek(fp,oldpos,SEEK_SET);
  3698. #endif
  3699.   return size;
  3700. }
  3701.  
  3702. /* root dir, with ending / */
  3703. typedef struct {
  3704.   char path[1024+4];
  3705.   int init;
  3706. } hts_rootdir_strc;
  3707. HTSEXT_API char* hts_rootdir(char* file) {
  3708.   static hts_rootdir_strc strc = {"", 0};
  3709.   //NOSTATIC_RESERVE(strc, hts_rootdir_strc, 1);
  3710.   if (file) {
  3711.     if (!strc.init) {
  3712.       strc.path[0]='\0';
  3713.       strc.init=1;
  3714.       if (strnotempty(file)) {
  3715.         char* a;
  3716.         strcpybuff(strc.path,file);
  3717.         while((a=strrchr(strc.path,'\\'))) *a='/';
  3718.         if ((a=strrchr(strc.path,'/'))) {
  3719.           *(a+1)='\0';
  3720.         } else
  3721.           strc.path[0]='\0';
  3722.       }
  3723.       if (!strnotempty(strc.path)) {
  3724.         if( getcwd( strc.path, 1024 ) == NULL )
  3725.             strc.path[0]='\0';
  3726.         else
  3727.           strcatbuff(strc.path,"/");
  3728.       }
  3729.     }
  3730.     return NULL;
  3731.   } else if (strc.init)
  3732.     return strc.path;
  3733.   else
  3734.     return "";
  3735. }
  3736.  
  3737.  
  3738.  
  3739. HTSEXT_API hts_stat_struct HTS_STAT;
  3740. //
  3741. // return  number of downloadable bytes, depending on rate limiter
  3742. // see engine_stats() routine, too
  3743. // this routine works quite well for big files and regular ones, but apparently the rate limiter has
  3744. // some problems with very small files (rate too high)
  3745. LLint check_downloadable_bytes(int rate) {
  3746.   if (rate>0) {
  3747.     TStamp time_now;
  3748.     TStamp elapsed_useconds;
  3749.     LLint bytes_transfered_during_period;
  3750.     LLint left;
  3751.  
  3752.     // get the older timer
  3753.     int id_timer = (HTS_STAT.istat_idlasttimer + 1) % 2;
  3754.  
  3755.     time_now=mtime_local();
  3756.     elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
  3757.     // NO totally stupid - elapsed_useconds+=1000;      // for the next second, too
  3758.     bytes_transfered_during_period = (HTS_STAT.HTS_TOTAL_RECV-HTS_STAT.istat_bytes[id_timer]);
  3759.     
  3760.     left = ((rate * elapsed_useconds)/1000) - bytes_transfered_during_period;
  3761.     if (left <= 0)
  3762.       left = 0;
  3763.     
  3764.     return left;
  3765.   } else
  3766.     return TAILLE_BUFFER;
  3767. }
  3768.  
  3769. //
  3770. // 0 : OK
  3771. // 1 : slow down
  3772. #if 0
  3773. int HTS_TOTAL_RECV_CHECK(int var) {
  3774.   if (HTS_STAT.HTS_TOTAL_RECV_STATE)
  3775.     return 1;
  3776.     /*
  3777.     {
  3778.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  3779.       var = min(var,32); 
  3780.       Sleep(250); 
  3781.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  3782.       var = min(var,256); 
  3783.       Sleep(100); 
  3784.     } else { 
  3785.       var/=2; 
  3786.       if (var<=0) var=1; 
  3787.       Sleep(50); 
  3788.     } 
  3789.   }
  3790.     */
  3791.   return 0;
  3792. }
  3793. #endif
  3794.  
  3795. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  3796. // >0 : data received
  3797. // == 0 : not yet data
  3798. // <0 : no more data or error
  3799. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  3800.   int retour;
  3801.   //  return read(soc,buff,size);
  3802.   if (r->is_file) {
  3803. #if HTS_WIDE_DEBUG    
  3804.     DEBUG_W("read\n");
  3805. #endif
  3806.     if (r->fp)
  3807.       retour=(int)fread(buff,1,size,r->fp);
  3808.     else
  3809.       retour=-1;
  3810.   } else {
  3811. #if HTS_WIDE_DEBUG    
  3812.     DEBUG_W("recv\n");
  3813.     if (r->soc==INVALID_SOCKET)
  3814.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  3815. #endif
  3816.     //HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  3817. #if HTS_USEOPENSSL
  3818.     if (SSL_is_available && r->ssl) {
  3819.       retour = SSL_read(r->ssl_con, buff, size);
  3820.       if (retour <= 0) {
  3821.         int err_code = SSL_get_error(r->ssl_con, retour);
  3822.         if (
  3823.           (err_code == SSL_ERROR_WANT_READ)
  3824.           ||
  3825.           (err_code == SSL_ERROR_WANT_WRITE)
  3826.           ) 
  3827.         {
  3828.           retour = 0;             /* no data yet (ssl cache) */
  3829.         } else {
  3830.           retour = -1;            /* eof or error */
  3831.         }
  3832.       }
  3833.     } else {
  3834. #endif
  3835.     retour=recv(r->soc,buff,size,0);
  3836.   }
  3837.   if (retour > 0)    // compter flux entrant
  3838.     HTS_STAT.HTS_TOTAL_RECV+=retour;
  3839. #if HTS_USEOPENSSL
  3840.   }
  3841. #endif
  3842. #if HTS_WIDE_DEBUG    
  3843.   DEBUG_W("recv/read done\n");
  3844. #endif
  3845.   return retour;
  3846. }
  3847.  
  3848.  
  3849. // -- Gestion cache DNS --
  3850. // 'RX98
  3851. #if HTS_DNSCACHE
  3852.  
  3853. // 'capsule' contenant uniquement le cache
  3854. t_dnscache* _hts_cache(void) {
  3855.   t_dnscache* cache;
  3856.   NOSTATIC_RESERVE(cache, t_dnscache, 1);
  3857.   return cache;
  3858. }
  3859.  
  3860. // lock le cache dns pour tout opΘration d'ajout
  3861. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  3862. // -1: status? 0: libΘrer 1:locker
  3863.  
  3864. /* 
  3865.   Simple lock function for cache
  3866.  
  3867.   Return value: always 0
  3868.   Parameter:
  3869.   1 wait for lock (mutex) available and lock it
  3870.   0 unlock the mutex
  3871.   [-1 check if locked (always return 0 with mutex)]
  3872.   -999 initialize
  3873. */
  3874. #if USE_BEGINTHREAD
  3875. int _hts_lockdns(int i) {
  3876.   static PTHREAD_LOCK_TYPE hMutex; 
  3877.   return htsSetLock(&hMutex,i);
  3878. }
  3879. #else
  3880. int _hts_lockdns(int i) {
  3881.   int l=0;
  3882.   if (i>=0)
  3883.     l=i;
  3884.   return l;
  3885. }
  3886. #endif
  3887.  
  3888. // routine pour le cache - retour optionnel α donner α chaque fois
  3889. // NULL: nom non encore testΘ dans le cache
  3890. // si h_length==0 alors le nom n'existe pas dans le dns
  3891. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  3892.   // attendre que le cache dns soit prΩt
  3893.   while(_hts_lockdns(-1));  // attendre libΘration
  3894.   _hts_lockdns(1);          // locker
  3895.  
  3896.   while(1) {
  3897.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  3898.       if (cache->host_length>0) {  // entrΘe valide
  3899.         if (retour->h_addr_list[0])
  3900.           memcpy(retour->h_addr_list[0], cache->host_addr, cache->host_length);
  3901.         retour->h_length=cache->host_length;
  3902.       } else if (cache->host_length==0) {  // en cours
  3903.         _hts_lockdns(0);          // dΘlocker
  3904.         return NULL;
  3905.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  3906.         if (retour->h_addr_list[0])
  3907.           retour->h_addr_list[0][0]='\0';
  3908.         retour->h_length=0;  // erreur, n'existe pas
  3909.       }
  3910.       _hts_lockdns(0);          // dΘlocker
  3911.       return retour;
  3912.     } else {    // on a pas encore trouvΘ
  3913.       if (cache->n!=NULL) { // chercher encore
  3914.         cache=cache->n;   // suivant!
  3915.       } else {
  3916.         _hts_lockdns(0);          // dΘlocker
  3917.         return NULL;    // non prΘsent        
  3918.       }
  3919.     }    
  3920.   }
  3921. }
  3922.  
  3923. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  3924. // 0 non encore
  3925. // 1 ok
  3926. // 2 non prΘsent
  3927. int hts_dnstest(char* _iadr) {
  3928.   char* iadr;
  3929.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  3930.   NOSTATIC_RESERVE(iadr, char, HTS_URLMAXSIZE*2);
  3931.  
  3932.   // sauter user:pass@ Θventuel
  3933.   strcpybuff(iadr,jump_identification(_iadr));
  3934.   // couper Θventuel :
  3935.   {
  3936.     char *a;
  3937.     if ( (a=jump_toport(iadr)) )
  3938.       *a='\0';
  3939.   }
  3940.  
  3941. #if HTS_WIN
  3942.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  3943. #else
  3944.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  3945. #endif
  3946.     return 1;
  3947.  
  3948.   while(_hts_lockdns(-1));  // attendre libΘration
  3949.   _hts_lockdns(1);          // locker
  3950.   while(1) {
  3951.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  3952.       _hts_lockdns(0);          // dΘlocker
  3953.       return 1;    // prΘsent!
  3954.     } else {    // on a pas encore trouvΘ
  3955.       if (cache->n!=NULL) { // chercher encore
  3956.         cache=cache->n;   // suivant!
  3957.       } else {
  3958.         _hts_lockdns(0);          // dΘlocker
  3959.         return 2;    // non prΘsent        
  3960.       }
  3961.     }    
  3962.   }
  3963. }
  3964.  
  3965.  
  3966. HTSEXT_API t_hostent* vxgethostbyname(char* hostname, void* v_buffer) {
  3967.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  3968.   /* Clear */
  3969.   fullhostent_init(buffer);
  3970.  
  3971.   /* Protection */
  3972.   if (!strnotempty(hostname)) {
  3973.     return NULL;
  3974.   }
  3975.  
  3976.   /* 
  3977.     Strip [] if any : [3ffe:b80:1234:1::1] 
  3978.     The resolver doesn't seem to handle IP6 addresses in brackets
  3979.   */
  3980.   if ((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) {
  3981.     char tempo[HTS_URLMAXSIZE*2];
  3982.     tempo[0]='\0';
  3983.     strncatbuff(tempo, hostname+1, strlen(hostname)-2);
  3984.     strcpybuff(hostname, tempo);
  3985.   }
  3986.  
  3987.   {
  3988. #if HTS_INET6==0
  3989.   /*
  3990.   ipV4 resolver
  3991.     */
  3992.     t_hostent* hp=gethostbyname(hostname);
  3993.     if (hp!=NULL) {
  3994.       if ( (hp->h_length) && ( ((unsigned int) hp->h_length) <= buffer->addr_maxlen) ) {
  3995.         memcpy(buffer->hp.h_addr_list[0], hp->h_addr_list[0], hp->h_length);
  3996.         buffer->hp.h_length = hp->h_length;
  3997.         return &(buffer->hp);
  3998.       }
  3999.     }
  4000. #else
  4001.     /*
  4002.     ipV6 resolver
  4003.     */
  4004.     /*
  4005.     int error_num=0;
  4006.     t_hostent* hp=getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &error_num);
  4007.     oops, deprecated :(
  4008.     */
  4009.     struct addrinfo* res = NULL;
  4010.     struct addrinfo hints;
  4011.     memset(&hints, 0, sizeof(hints));
  4012.     if (IPV6_resolver == 1)        // V4 only (for bogus V6 entries)
  4013.       hints.ai_family = PF_INET;
  4014.     else if (IPV6_resolver == 2)   // V6 only (for testing V6 only)
  4015.       hints.ai_family = PF_INET6;
  4016.     else                           // V4 + V6
  4017.       hints.ai_family = PF_UNSPEC;
  4018.     hints.ai_socktype = SOCK_STREAM;
  4019.     hints.ai_protocol = IPPROTO_TCP;
  4020.     if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
  4021.       if (res) {
  4022.         if ( (res->ai_addr) && (res->ai_addrlen) && (res->ai_addrlen <= buffer->addr_maxlen) ) {
  4023.           memcpy(buffer->hp.h_addr_list[0], res->ai_addr, res->ai_addrlen);
  4024.           buffer->hp.h_length = res->ai_addrlen;
  4025.           freeaddrinfo(res);
  4026.           return &(buffer->hp);
  4027.         }
  4028.       }
  4029.     }
  4030.     if (res) {
  4031.       freeaddrinfo(res);
  4032.     }
  4033.     
  4034. #endif
  4035.   }
  4036.   return NULL;
  4037. }
  4038.  
  4039. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  4040. t_hostent* hts_gethostbyname(char* _iadr, void* v_buffer) {
  4041.   char iadr[HTS_URLMAXSIZE*2];
  4042.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4043.   t_dnscache* cache=_hts_cache();  // adresse du cache
  4044.   t_hostent* hp;
  4045.  
  4046.   /* Clear */
  4047.   fullhostent_init(buffer);
  4048.  
  4049.   strcpybuff(iadr,jump_identification(_iadr));
  4050.   // couper Θventuel :
  4051.   {
  4052.     char *a;
  4053.     if ( (a=jump_toport(iadr)) )
  4054.       *a='\0';
  4055.   }
  4056.  
  4057.   // effacer structure de retour, crΘer nouvelle
  4058.   /*
  4059.   memset(&host, 0, sizeof(t_hostent));  
  4060.   host.h_addr_list=he;
  4061.   he[0]=NULL;
  4062.   he[1]=NULL;  
  4063.   host.h_length=0;  
  4064.   */
  4065.   cache->iadr[0]='*';
  4066.   cache->iadr[1]='\0';
  4067.   
  4068.   /* get IP from the dns cache */
  4069.   hp = _hts_ghbn(cache, iadr, &buffer->hp);
  4070.   if (hp) {
  4071.     if (hp->h_length>0)
  4072.       return hp;
  4073.     else
  4074.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  4075.   } else {  // non prΘsent dans le cache dns, tester
  4076.     t_dnscache* c=cache;
  4077.     while(c->n) c=c->n;    // calculer queue
  4078.     
  4079. #if HTS_WIDE_DEBUG    
  4080.     DEBUG_W("gethostbyname\n");
  4081. #endif      
  4082. #if HDEBUG
  4083.     printf("gethostbyname (not in cache)\n");
  4084. #endif
  4085.     {
  4086.       unsigned long inetaddr;
  4087. #if HTS_WIN
  4088.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  4089. #else
  4090.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  4091. #endif        
  4092. #if DEBUGDNS 
  4093.         printf("resolving (not cached) %s\n",iadr);
  4094. #endif
  4095.         hp=vxgethostbyname(iadr, buffer);  // calculer IP host
  4096.       } else {     // numΘrique, convertir sans passer par le dns
  4097.         buffer->hp.h_addr_list[0]=(char*) &inetaddr;
  4098.         buffer->hp.h_length=4;
  4099.         hp=&buffer->hp;
  4100.       }
  4101.     }
  4102. #if HTS_WIDE_DEBUG    
  4103.     DEBUG_W("gethostbyname done\n");
  4104. #endif
  4105.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  4106.     if (cache->n!=NULL) {
  4107.       strcpybuff(cache->n->iadr,iadr);
  4108.       if (hp!=NULL) {
  4109.         memcpy(cache->n->host_addr, hp->h_addr_list[0], hp->h_length);
  4110.         cache->n->host_length=hp->h_length;
  4111.       } else {
  4112.         cache->n->host_addr[0]='\0';
  4113.         cache->n->host_length=0;  // non existant dans le dns
  4114.       }
  4115.       cache->n->n=NULL;
  4116.       return hp;
  4117.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  4118.       return hp;
  4119.     }        
  4120.   }  // retour hp du cache
  4121. }
  4122.  
  4123. #else
  4124. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr, t_fullhostent* buffer) {
  4125.   t_hostent* retour;
  4126. #if HTS_WIDE_DEBUG    
  4127.   DEBUG_W("gethostbyname (2)\n");
  4128. #endif
  4129. #if DEBUGDNS 
  4130.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  4131. #endif
  4132.   retour=vxgethostbyname(jump_identification(iadr), );
  4133. #if HTS_WIDE_DEBUG    
  4134.   DEBUG_W("gethostbyname (2) done\n");
  4135. #endif
  4136.   return retour;
  4137. }
  4138. #endif
  4139.  
  4140.  
  4141. // --- Tracage des mallocs() ---
  4142. #ifdef HTS_TRACE_MALLOC
  4143. //#define htsLocker(A, N) htsLocker(A, N)
  4144. #define htsLocker(A, N) do {} while(0)
  4145. static mlink trmalloc = {NULL,0,0,NULL};
  4146. static int trmalloc_id=0;
  4147. static PTHREAD_LOCK_TYPE* mallocMutex = NULL;
  4148. static void hts_meminit(void) {
  4149.   //if (mallocMutex == NULL) {
  4150.   //  mallocMutex = calloc(sizeof(*mallocMutex), 1);
  4151.   //  htsLocker(mallocMutex, -999);
  4152.   //}
  4153. }
  4154. void* hts_malloc(size_t len) {
  4155.   void* adr;
  4156.   hts_meminit();
  4157.   htsLocker(mallocMutex, 1);
  4158.   fassert(len > 0);
  4159.   adr = hts_xmalloc(len, 0);
  4160.   htsLocker(mallocMutex, 0);
  4161.   return adr;
  4162. }
  4163. void* hts_calloc(size_t len,size_t len2) {
  4164.   void* adr;
  4165.   hts_meminit();
  4166.   fassert(len > 0);
  4167.   fassert(len2 > 0);
  4168.   htsLocker(mallocMutex, 1);
  4169.   adr = hts_xmalloc(len, len2);
  4170.   htsLocker(mallocMutex, 0);
  4171.   memset(adr, 0, len * len2);
  4172.   return adr;
  4173. }
  4174. void* hts_xmalloc(size_t len,size_t len2) {
  4175.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  4176.   fassert(lnk != NULL);
  4177.   fassert(len > 0);
  4178.   fassert(len2 >= 0);
  4179.   if (lnk) {
  4180.     void*  r   = NULL;
  4181.     int size, bsize = sizeof(t_htsboundary);
  4182.     if (len2)
  4183.       size = len * len2;
  4184.     else
  4185.       size = len;
  4186.     size += ((bsize - (size % bsize)) % bsize);  /* check alignement */
  4187.     r = malloc(size + bsize*2);
  4188.     fassert(r != NULL);
  4189.     if (r) {
  4190.       * ( (t_htsboundary*) ((char*) r ) ) 
  4191.         = * ( (t_htsboundary*) ( (char*) r + size + bsize ) )
  4192.         = htsboundary;
  4193.       ((char*) r) += bsize;    /* boundary */
  4194.       lnk->adr = r;
  4195.       lnk->len = size;
  4196.       lnk->id = trmalloc_id++;
  4197.       lnk->next = trmalloc.next;
  4198.       trmalloc.next = lnk;
  4199.       return r;
  4200.     } else {
  4201.       free(lnk);
  4202.     }
  4203.   }
  4204.   return NULL;
  4205. }
  4206. void hts_free(void* adr) {
  4207.   mlink* lnk = &trmalloc;
  4208.   int bsize = sizeof(t_htsboundary);
  4209.   fassert(adr != NULL);
  4210.   if (!adr) {
  4211.     return;
  4212.   }
  4213.   htsLocker(mallocMutex, 1);
  4214.   while(lnk->next != NULL) {
  4215.     if (lnk->next->adr == adr) {
  4216.       mlink* blk_free=lnk->next;
  4217.       fassert(blk_free->id != -1);
  4218.       fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4219.       fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4220.       lnk->next=lnk->next->next;
  4221.       free((void*) blk_free);
  4222.       //blk_free->id=-1;
  4223.       free((char*) adr - bsize);
  4224.       htsLocker(mallocMutex, 0);
  4225.       return;
  4226.     }
  4227.     lnk = lnk->next;
  4228.     fassert(lnk->next != NULL);
  4229.   }
  4230.   free(adr);
  4231.   htsLocker(mallocMutex, 0);
  4232. }
  4233. void* hts_realloc(void* adr,size_t len) {
  4234.   int bsize = sizeof(t_htsboundary);
  4235.   len += ((bsize - (len % bsize)) % bsize);  /* check alignement */
  4236.   if (adr != NULL) {
  4237.     mlink* lnk = &trmalloc;
  4238.     htsLocker(mallocMutex, 1);
  4239.     while(lnk->next != NULL)  {
  4240.       if (lnk->next->adr==adr) {
  4241.         {
  4242.           mlink* blk_free=lnk->next;
  4243.           fassert(blk_free->id != -1);
  4244.           fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4245.           fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4246.         }
  4247.         adr = realloc((char*) adr - bsize, len + bsize * 2);
  4248.         fassert(adr != NULL);
  4249.         lnk->next->adr = (char*) adr + bsize;
  4250.         lnk->next->len = len;
  4251.         * ( (t_htsboundary*) ( (char*) adr ) ) 
  4252.           = * ( (t_htsboundary*) ( (char*) adr + len + bsize) ) 
  4253.           = htsboundary;
  4254.         htsLocker(mallocMutex, 0);
  4255.         return (char*) adr + bsize;
  4256.       }
  4257.       lnk = lnk->next;
  4258.       fassert(lnk->next != NULL);
  4259.     }
  4260.     htsLocker(mallocMutex, 0);
  4261.   }
  4262.   return hts_malloc(len);
  4263. }
  4264. mlink* hts_find(char* adr) {
  4265.   char* stkframe = (char*) &stkframe;
  4266.   mlink* lnk = &trmalloc;
  4267.   int bsize = sizeof(t_htsboundary);
  4268.   fassert(adr != NULL);
  4269.   if (!adr) {
  4270.     return NULL;
  4271.   }
  4272.   htsLocker(mallocMutex, 1);
  4273.   while(lnk->next != NULL) {
  4274.     if (adr >= lnk->next->adr && adr <= lnk->next->adr + lnk->next->len) {   /* found */
  4275.       htsLocker(mallocMutex, 0);
  4276.       return lnk->next;
  4277.     }
  4278.     lnk = lnk->next;
  4279.   }
  4280.   htsLocker(mallocMutex, 0);
  4281.   {
  4282.     int depl = (int) (adr - stkframe);
  4283.     if (depl < 0) depl = -depl;
  4284.     //fassert(depl < 512000);   /* near the stack frame.. doesn't look like malloc but stack variable */
  4285.     return NULL;
  4286.   }
  4287. }
  4288. // check the malloct() and calloct() trace stack
  4289. void  hts_freeall(void) {
  4290.   int bsize = sizeof(t_htsboundary);
  4291.   while(trmalloc.next) {
  4292. #if MEMDEBUG
  4293.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  4294. #endif
  4295.     if (trmalloc.next->id != -1) {
  4296.       free((char*) trmalloc.next->adr - bsize);
  4297.     }
  4298.   }
  4299. }
  4300. #endif
  4301.  
  4302.  
  4303. // -- divers //
  4304.  
  4305. // cut path and project name
  4306. // patch also initial path
  4307. void cut_path(char* fullpath,char* path,char* pname) {
  4308.   path[0]=pname[0]='\0';
  4309.   if (strnotempty(fullpath)) {
  4310.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  4311.       fullpath[strlen(fullpath)-1]='\0';
  4312.     if (strlen(fullpath)>1) {
  4313.       char* a;
  4314.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  4315.       a=fullpath+strlen(fullpath)-2;
  4316.       while( (*a!='/') && ( a > fullpath)) a--;
  4317.       if (*a=='/') a++;
  4318.       strcpybuff(pname,a);
  4319.       strncatbuff(path,fullpath,(int) (a - fullpath));
  4320.     }
  4321.   }
  4322. }
  4323.  
  4324.  
  4325.  
  4326. // -- Gestion protocole ftp --
  4327.  
  4328. #if HTS_WIN
  4329. int ftp_available(void) {
  4330.   return 1;
  4331. }
  4332. #else
  4333. int ftp_available(void) {
  4334.   return 1;   // ok!
  4335.   //return 0;   // SOUS UNIX, PROBLEMES
  4336. }
  4337. #endif
  4338.  
  4339.  
  4340.  
  4341. HTSEXT_API int hts_init(void) {
  4342.   static int hts_init_ok = 0;
  4343.  
  4344.   /* Ensure external modules are loaded */
  4345.   htspe_init();
  4346.  
  4347.   if (!hts_init_ok) {
  4348.     hts_init_ok = 1;
  4349.     // default wrappers
  4350.     htswrap_init();
  4351.     htswrap_add("init",htsdefault_init);
  4352.     htswrap_add("free",htsdefault_uninit);
  4353.     htswrap_add("start",htsdefault_start);
  4354.     htswrap_add("change-options",htsdefault_chopt);
  4355.     htswrap_add("end",htsdefault_end);
  4356.     htswrap_add("check-html",htsdefault_checkhtml);
  4357.     htswrap_add("loop",htsdefault_loop);
  4358.     htswrap_add("query",htsdefault_query);
  4359.     htswrap_add("query2",htsdefault_query2);
  4360.     htswrap_add("query3",htsdefault_query3);
  4361.     htswrap_add("check-link",htsdefault_check);
  4362.     htswrap_add("pause",htsdefault_pause);
  4363.     htswrap_add("save-file",htsdefault_filesave);
  4364.     htswrap_add("link-detected",htsdefault_linkdetected);
  4365.     htswrap_add("transfer-status",htsdefault_xfrstatus);
  4366.     htswrap_add("save-name",htsdefault_savename);
  4367.   }
  4368.   
  4369. #if HTS_USEOPENSSL
  4370.   /*
  4371.   Initialize the OpensSSL library
  4372.   */
  4373.   if (!openssl_ctx && SSL_is_available) {
  4374.     if (SSL_load_error_strings) SSL_load_error_strings();
  4375.     SSL_library_init();
  4376.     ///if (SSL_load_error_strings)  SSL_load_error_strings();
  4377.     //if (ERR_load_crypto_strings) ERR_load_crypto_strings();
  4378.     // if (ERR_load_SSL_strings)    ERR_load_SSL_strings(); ???!!!
  4379.     // OpenSSL_add_all_algorithms();
  4380.     openssl_ctx = SSL_CTX_new(SSLv23_client_method());
  4381.     if (!openssl_ctx) {
  4382.       fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)\n");
  4383.       abortLog("unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)");
  4384.       abort();
  4385.     }
  4386.   }
  4387. #endif
  4388.   
  4389.   /* Init vars and thread-specific values */
  4390.   hts_initvar();
  4391.   
  4392.   /* initialiser structcheck */
  4393.   structcheck_init(1);
  4394.  
  4395.   return 1;
  4396. }
  4397. HTSEXT_API int hts_uninit(void) {
  4398.   hts_freevar();
  4399.   /* htswrap_free(); */
  4400.   return 1;
  4401. }
  4402.  
  4403. // defaut wrappers
  4404. void __cdecl htsdefault_init(void) {
  4405. }
  4406. void __cdecl htsdefault_uninit(void) {
  4407.   hts_freevar();
  4408. }
  4409. int __cdecl htsdefault_start(void* opt) {
  4410.   return 1; 
  4411. }
  4412. int __cdecl htsdefault_chopt(void* opt) {
  4413.   return 1;
  4414. }
  4415. int  __cdecl htsdefault_end(void) { 
  4416.   return 1; 
  4417. }
  4418. int __cdecl htsdefault_checkhtml(char* html,int len,char* url_adresse,char* url_fichier) {
  4419.   return 1;
  4420. }
  4421. int __cdecl htsdefault_loop(void* back,int back_max,int back_index,int lien_n,int lien_tot,int stat_time,hts_stat_struct* stats) {    // appelΘ α chaque boucle de HTTrack
  4422.   return 1;
  4423. }
  4424. char* __cdecl htsdefault_query(char* question) {
  4425.   return "";
  4426. }
  4427. char* __cdecl htsdefault_query2(char* question) {
  4428.   return "";
  4429. }
  4430. char* __cdecl htsdefault_query3(char* question) {
  4431.   return "";
  4432. }
  4433. int __cdecl htsdefault_check(char* adr,char* fil,int status) {
  4434.   return -1;
  4435. }
  4436. void __cdecl htsdefault_pause(char* lockfile) {
  4437.   while (fexist(lockfile)) {
  4438.     Sleep(1000);
  4439.   }
  4440. }
  4441. void __cdecl htsdefault_filesave(char* file) {
  4442. }
  4443. int __cdecl htsdefault_linkdetected(char* link) {
  4444.   return 1;
  4445. }
  4446. int __cdecl htsdefault_xfrstatus(void* back) {
  4447.   return 1;
  4448. }
  4449. int __cdecl htsdefault_savename(char* adr_complete,char* fil_complete,char* referer_adr,char* referer_fil,char* save) {
  4450.   return 1;
  4451. }
  4452. // end defaut wrappers
  4453.  
  4454.  
  4455.  
  4456. // Fin
  4457.  
  4458.